From d1dc6e50b16bf151734131796bb1061ff3081db2 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Wed, 12 Jul 2023 21:20:36 +0200 Subject: [PATCH] Enhance computation of system-package provided by a ExecutionEnvironment - Only consider EE of running VM in launch validation to match the behavior later at runtime - For the PDEState the EE's system-package is computed with the following distinction: - for a EE that corresponds to a Java-9 or higher release, get the 'best matching' VMInstall and query the system-packages for the EE's java release version (which is possible for modular JVMs) - for a Java-8 or lower release check if there is a VMInstall selected/strictly compatible to that version and query the system-packages from that VM (i.e. its rt.jar and other libraries) - if there is no VMInstall for a for a Java-8 or lower release, combine the hard-coded list of 'java.*' packages with the set of non-java packages provided by the default VMInstall of the workspace. The default VMInstall of the WS is at the same time the JVM selected in the active target definition (which sets its selection as WS default upon loading). Fixes https://github.com/eclipse-pde/eclipse.pde/issues/429 --- .../pde/internal/build/site/PDEState.java | 235 ++++++++++++++++-- .../internal/core/TargetPlatformHelper.java | 69 +---- .../launcher/LaunchValidationOperation.java | 23 +- 3 files changed, 232 insertions(+), 95 deletions(-) diff --git a/build/org.eclipse.pde.build/src/org/eclipse/pde/internal/build/site/PDEState.java b/build/org.eclipse.pde.build/src/org/eclipse/pde/internal/build/site/PDEState.java index ad4468b34f2..e34dcb87a86 100644 --- a/build/org.eclipse.pde.build/src/org/eclipse/pde/internal/build/site/PDEState.java +++ b/build/org.eclipse.pde.build/src/org/eclipse/pde/internal/build/site/PDEState.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2021 IBM Corporation and others. + * Copyright (c) 2004, 2023 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -10,6 +10,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Hannes Wellmann - Enhance computation of system-package provided by a ExecutionEnvironment *******************************************************************************/ package org.eclipse.pde.internal.build.site; @@ -30,8 +31,9 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.TreeSet; +import java.util.function.Function; import java.util.jar.JarFile; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -44,6 +46,7 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; +import org.eclipse.jdt.launching.LibraryLocation; import org.eclipse.jdt.launching.environments.IExecutionEnvironment; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.ExportPackageDescription; @@ -481,14 +484,215 @@ public void resolveState() { } public static String querySystemPackages(IExecutionEnvironment environment) { - // Copy of org.eclipse.pde.internal.core.TargetPlatformHelper.querySystemPackages() - IVMInstall vm = bestVmInstallFor(environment); - if (vm == null || !JavaRuntime.isModularJava(vm)) { + if (environment == null) { + return null; + } + Integer releaseVersion = readJavaReleaseVersion(environment); + if (releaseVersion == null) { return null; } - String release = environment.getProfileProperties().getProperty(JavaCore.COMPILER_COMPLIANCE); + Collection systemPackages; + if (releaseVersion <= 8) { + IVMInstall eeVM = environment.getDefaultVM(); + IVMInstall vm = bestVmInstallFor(environment, vms -> null); // TODO: also consider perfect matches? + if (eeVM != null) { + // In case a VM is selected for an EE, query that VM and use its system-packages + systemPackages = querySystemPackages(eeVM, null); + } else { + // No VM selected for the non-modular EE, compose list of available system-packages from the predefined list of java-packages plus the non-java packages of the WS default VM + IVMInstall targetVM = JavaRuntime.getDefaultVMInstall(); // Set by the Target-Definition if specified there + Collection targetVMSystemPackages = querySystemPackages(targetVM, null); + if (targetVMSystemPackages == null) { + return null; + } + Stream targetVMNonJavaPackages = targetVMSystemPackages.stream().filter(p -> !p.startsWith("java.")); //$NON-NLS-1$ + Stream javaPackages = PRE_JAVA_9_SYSTEM_PACKAGES.get(releaseVersion).stream(); + systemPackages = Stream.concat(javaPackages, targetVMNonJavaPackages).sorted().toList(); + } + } else { + IVMInstall vm = bestVmInstallFor(environment, vms -> vms[0]); + if (vm == null) { + return null; + } + systemPackages = querySystemPackages(vm, environment); + } + return String.join(",", systemPackages); //$NON-NLS-1$ + } + + //TODO: fill empty lists + @SuppressWarnings("nls") + private static final List> PRE_JAVA_9_SYSTEM_PACKAGES = List.of( + // Java 1.0 + List.of(), + // Java 1.1 + List.of(), + // Java 1.2 + List.of("java.applet", // + "java.awt", // + "java.awt.color", // + "java.awt.datatransfer", // + "java.awt.dnd", // + "java.awt.dnd.peer", // + "java.awt.event", // + "java.awt.font", // + "java.awt.geom", // + "java.awt.im", // + "java.awt.image", // + "java.awt.image.renderable", // + "java.awt.peer", // + "java.awt.print", // + "java.awt.resources", // + "java.beans", // + "java.beans.beancontext", // + "java.io", // + "java.lang", // + "java.lang.ref", // + "java.lang.reflect", // + "java.math", // + "java.net", // + "java.rmi", // + "java.rmi.activation", // + "java.rmi.dgc", // + "java.rmi.registry", // + "java.rmi.server", // + "java.security", // + "java.security.acl", // + "java.security.cert", // + "java.security.interfaces", // + "java.security.spec", // + "java.sql", // + "java.text", // + "java.text.resources", // + "java.util", // + "java.util.jar", // + "java.util.zip"), + // Java 1.3 + List.of(), + // Java 1.4 + List.of(), + // Java 1.5 + List.of(), + // Java 1.6 + List.of(), + // Java 1.7 + List.of(), + // Java 1.8 + List.of("java.applet", // + "java.awt", // + "java.awt.color", // + "java.awt.datatransfer", // + "java.awt.dnd", // + "java.awt.dnd.peer", // + "java.awt.event", // + "java.awt.font", // + "java.awt.geom", // + "java.awt.im", // + "java.awt.im.spi", // + "java.awt.image", // + "java.awt.image.renderable", // + "java.awt.peer", // + "java.awt.print", // + "java.beans", // + "java.beans.beancontext", // + "java.io", // + "java.lang", // + "java.lang.annotation", // + "java.lang.instrument", // + "java.lang.invoke", // + "java.lang.management", // + "java.lang.ref", // + "java.lang.reflect", // + "java.math", // + "java.net", // + "java.nio", // + "java.nio.channels", // + "java.nio.channels.spi", // + "java.nio.charset", // + "java.nio.charset.spi", // + "java.nio.file", // + "java.nio.file.attribute", // + "java.nio.file.spi", // + "java.rmi", // + "java.rmi.activation", // + "java.rmi.dgc", // + "java.rmi.registry", // + "java.rmi.server", // + "java.security", // + "java.security.acl", // + "java.security.cert", // + "java.security.interfaces", // + "java.security.spec", // + "java.sql", // + "java.text", // + "java.text.spi", // + "java.time", // + "java.time.chrono", // + "java.time.format", // + "java.time.temporal", // + "java.time.zone", // + "java.util", // + "java.util.concurrent", // + "java.util.concurrent.atomic", // + "java.util.concurrent.locks", // + "java.util.function", // + "java.util.jar", // + "java.util.logging", // + "java.util.prefs", // + "java.util.regex", // + "java.util.spi", // + "java.util.stream", // + "java.util.zip")); + + @SuppressWarnings("nls") + private static final Map JDK_ID_RELEASE = Map.of( // + //TODO: add zero? + "JRE-1.1", 1, // + "J2SE-1.2", 2, // + "J2SE-1.3", 3, // + "J2SE-1.4", 4, // + "J2SE-1.5", 5, // + "JavaSE-1.6", 6, // + "JavaSE-1.7", 7, // + "JavaSE-1.8", 8); + + private static Integer readJavaReleaseVersion(IExecutionEnvironment environment) { + String id = environment.getId(); + if (id.startsWith("JavaSE-")) { //$NON-NLS-1$ + try { + return Integer.parseInt(id.substring("JavaSE-".length())); //$NON-NLS-1$ + } catch (NumberFormatException e) { // Another EE + } + } + return JDK_ID_RELEASE.get(id); + } + + /** + * Returns t + * @param vm the VM to query + * @param environment the release EE to use or null, if the VM's release should be used + */ + private static Collection querySystemPackages(IVMInstall vm, IExecutionEnvironment environment) { + if (!JavaRuntime.isModularJava(vm)) { + Collection packages = new HashSet<>(); + for (LibraryLocation libLocation : JavaRuntime.getLibraryLocations(vm)) { + IPath path = libLocation.getSystemLibraryPath(); + if (path != null) { + try (ZipFile zip = new ZipFile(path.toFile())) { + zip.stream().filter(e -> !e.isDirectory()).map(ZipEntry::getName).filter(n -> !n.startsWith("META-INF/")).map(n -> { //$NON-NLS-1$ + int i = n.lastIndexOf('/'); + return n.substring(0, i); + }).distinct().map(n -> n.replace('/', '.')).forEach(packages::add); + } catch (IOException e) { + ILog.get().error("Failed to read packages in JVM library for " + vm + ", at " + path, e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + return packages; + } + + String release = environment != null ? environment.getProfileProperties().getProperty(JavaCore.COMPILER_COMPLIANCE) : null; try { - Collection packages = new TreeSet<>(); + Collection packages = new HashSet<>(); String jrtPath = "lib/" + org.eclipse.jdt.internal.compiler.util.JRTUtil.JRT_FS_JAR; //$NON-NLS-1$ String path = new File(vm.getInstallLocation(), jrtPath).toString(); // $NON-NLS-1$ var jrt = org.eclipse.jdt.internal.core.builder.ClasspathLocation.forJrtSystem(path, null, null, release); @@ -503,17 +707,14 @@ public static String querySystemPackages(IExecutionEnvironment environment) { } } } - return String.join(",", packages); //$NON-NLS-1$ + return packages; } catch (CoreException e) { - ILog.of(PDEState.class).log(Status.error("failed to read system packages for " + environment, e)); //$NON-NLS-1$ + ILog.of(PDEState.class).log(Status.error("Failed to read system packages for " + environment, e)); //$NON-NLS-1$ } return null; } - private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment) { - if (environment == null) { - return null; - } + private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment, Function nonStrictDefaultSelector) { IVMInstall defaultVM = environment.getDefaultVM(); if (defaultVM != null) { return defaultVM; @@ -522,12 +723,8 @@ private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment) { if (compatible.length == 0) { return null; } - for (IVMInstall vm : compatible) { - if (environment.isStrictlyCompatible(vm)) { - return vm; - } - } - return compatible[0]; + IVMInstall nonStrictDefault = nonStrictDefaultSelector.apply(compatible); + return Arrays.stream(compatible).filter(environment::isStrictlyCompatible).findFirst().orElse(nonStrictDefault); } public State getState() { diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetPlatformHelper.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetPlatformHelper.java index 949274f5af4..e23f03d91c9 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetPlatformHelper.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetPlatformHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2022 IBM Corporation and others. + * Copyright (c) 2000, 2023 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -22,7 +22,6 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; @@ -45,8 +44,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.environments.IExecutionEnvironment; import org.eclipse.osgi.service.resolver.BundleDescription; @@ -354,14 +351,11 @@ public static Dictionary getTargetEnvironment(MinimalState state } @SuppressWarnings("unchecked") - public static Dictionary[] getPlatformProperties(String[] profiles, MinimalState state) { - if (profiles == null || profiles.length == 0) { - return new Dictionary[] { getTargetEnvironment(state) }; - } - + public static Dictionary[] getPlatformProperties(String[] profilesArr, MinimalState state) { + List profiles = profilesArr != null ? Arrays.asList(profilesArr) : List.of(); // add java profiles for those EE's that have a .profile file in the // current system bundle - List> result = new ArrayList<>(profiles.length); + List> result = new ArrayList<>(profiles.size()); for (String profile : profiles) { IExecutionEnvironment environment = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(profile); if (environment != null) { @@ -381,11 +375,10 @@ public static Dictionary[] getPlatformProperties(String[] profil public static void addEnvironmentProperties(Dictionary properties, IExecutionEnvironment environment, Properties profileProps) { - String systemPackages = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES); - if (systemPackages == null) { // java 10 and beyond - systemPackages = querySystemPackages(environment); - } + String systemPackages = querySystemPackages(environment); if (systemPackages != null) { + // The list of system-packages is often insufficient, always + // overwrite, if we have a more up-to-date one properties.put(Constants.FRAMEWORK_SYSTEMPACKAGES, systemPackages); } @SuppressWarnings("deprecation") @@ -396,54 +389,8 @@ public static void addEnvironmentProperties(Dictionary propertie } } - @SuppressWarnings("restriction") public static String querySystemPackages(IExecutionEnvironment environment) { - IVMInstall vm = bestVmInstallFor(environment); - if (vm == null || !JavaRuntime.isModularJava(vm)) { - return null; - } - String release = environment.getProfileProperties().getProperty(JavaCore.COMPILER_COMPLIANCE); - try { - Collection packages = new TreeSet<>(); - String jrtPath = "lib/" + org.eclipse.jdt.internal.compiler.util.JRTUtil.JRT_FS_JAR; //$NON-NLS-1$ - String path = new File(vm.getInstallLocation(), jrtPath).toString(); // $NON-NLS-1$ - var jrt = org.eclipse.jdt.internal.core.builder.ClasspathLocation.forJrtSystem(path, null, null, release); - for (String moduleName : jrt.getModuleNames(null)) { - var module = jrt.getModule(moduleName); - if (module == null) { - continue; - } - for (var packageExport : module.exports()) { - if (!packageExport.isQualified()) { - packages.add(new String(packageExport.name())); - } - } - } - return String.join(",", packages); //$NON-NLS-1$ - } catch (CoreException e) { - PDECore.logException(e, "failed to read system packages for " + environment); //$NON-NLS-1$ - } - return null; - } - - private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment) { - if (environment == null) { - return null; - } - IVMInstall defaultVM = environment.getDefaultVM(); - if (defaultVM != null) { - return defaultVM; - } - IVMInstall[] compatible = environment.getCompatibleVMs(); - if (compatible.length == 0) { - return null; - } - for (IVMInstall vm : compatible) { - if (environment.isStrictlyCompatible(vm)) { - return vm; - } - } - return compatible[0]; + return org.eclipse.pde.internal.build.site.PDEState.querySystemPackages(environment); } public static String[] getKnownExecutionEnvironments() { diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchValidationOperation.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchValidationOperation.java index 58d6b1da974..0d481473794 100644 --- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchValidationOperation.java +++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchValidationOperation.java @@ -17,10 +17,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Arrays; import java.util.Dictionary; -import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -60,27 +58,22 @@ public void run(IProgressMonitor monitor) throws CoreException { @SuppressWarnings("unchecked") protected Dictionary[] getPlatformProperties() throws CoreException { IExecutionEnvironment[] envs = getMatchingEnvironments(); - if (envs.length == 0) { - return new Dictionary[] {TargetPlatformHelper.getTargetEnvironment()}; - } - // add java profiles for those EE's that have a .profile file in the current system bundle - List> result = new ArrayList<>(envs.length); - for (IExecutionEnvironment env : envs) { + Dictionary environmentProperties = TargetPlatformHelper.getTargetEnvironment(); + // Only add the highest EE of the supplied VM, to match the runtime behavior + for (int i = envs.length - 1; i > 0; i--) { + IExecutionEnvironment env = envs[i]; + // add java profiles for those EE's that have a .profile file in the current system bundle Properties profileProps = getJavaProfileProperties(env.getId()); if (profileProps == null) { // Java10 onwards, we take profile via this method profileProps = env.getProfileProperties(); } if (profileProps != null) { - Dictionary props = TargetPlatformHelper.getTargetEnvironment(); - TargetPlatformHelper.addEnvironmentProperties(props, env, profileProps); - result.add(props); + TargetPlatformHelper.addEnvironmentProperties(environmentProperties, env, profileProps); + break; } } - if (!result.isEmpty()) { - return result.toArray(Dictionary[]::new); - } - return new Dictionary[] {TargetPlatformHelper.getTargetEnvironment()}; + return new Dictionary[] {environmentProperties}; } protected IExecutionEnvironment[] getMatchingEnvironments() throws CoreException {