Skip to content

Commit 24e9bb5

Browse files
committed
Enhance computation of system-package provided by a ExecutionEnvironment
- In the Product or OSGi-app launch validation only consider EE of the VM that will run the app, match the later runtime-behavior - 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). - In general the available system-packages are only really known at runtime. Therefore at any other time, e.g. in the workspace, one can only guess/assume what packages are available and the implemented algorithm seems to be the best trade-off between probable accuracy, convenience and the possibility to let the user control the result. - Listen to changes of available VMInstalls and ExecutionEnvironment defaults. Re-read them on changes and re-resolve the PDE-State again with a subsequent re-validation of all Plugin projects. - Adapt existing test-cases that expected some packages to be reported as present although were not. Fixes #429
1 parent 8435fdd commit 24e9bb5

File tree

10 files changed

+469
-157
lines changed

10 files changed

+469
-157
lines changed

apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiBaseline.java

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2007, 2022 IBM Corporation and others.
2+
* Copyright (c) 2007, 2023 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -290,14 +290,9 @@ public static Properties getJavaProfileProperties(String ee) {
290290
*/
291291
@SuppressWarnings("deprecation")
292292
private void initialize(Properties profile, ExecutionEnvironmentDescription description) throws CoreException {
293-
String value = profile.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES);
294-
if (value == null) {
295-
// In Java-10 and beyond, we query system-packages list from the JRE
296-
String environmentId = description.getProperty(ExecutionEnvironmentDescription.CLASS_LIB_LEVEL);
297-
IExecutionEnvironmentsManager manager = JavaRuntime.getExecutionEnvironmentsManager();
298-
IExecutionEnvironment environment = manager.getEnvironment(environmentId);
299-
value = TargetPlatformHelper.querySystemPackages(environment);
300-
}
293+
String environmentId = description.getProperty(ExecutionEnvironmentDescription.CLASS_LIB_LEVEL);
294+
IExecutionEnvironment ee = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(environmentId);
295+
String value = TargetPlatformHelper.getSystemPackages(ee, profile);
301296
String[] systemPackages = null;
302297
if (value != null) {
303298
systemPackages = value.split(","); //$NON-NLS-1$

build/org.eclipse.pde.build/src/org/eclipse/pde/internal/build/site/PDEState.java

+185-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2004, 2021 IBM Corporation and others.
2+
* Copyright (c) 2004, 2023 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
1010
*
1111
* Contributors:
1212
* IBM Corporation - initial API and implementation
13+
* Hannes Wellmann - Enhance computation of system-package provided by a ExecutionEnvironment
1314
*******************************************************************************/
1415
package org.eclipse.pde.internal.build.site;
1516

@@ -28,10 +29,14 @@
2829
import java.util.Hashtable;
2930
import java.util.List;
3031
import java.util.Map;
32+
import java.util.Optional;
3133
import java.util.Properties;
3234
import java.util.Set;
3335
import java.util.TreeSet;
36+
import java.util.function.Function;
3437
import java.util.jar.JarFile;
38+
import java.util.regex.Pattern;
39+
import java.util.stream.Stream;
3540
import java.util.zip.ZipEntry;
3641
import java.util.zip.ZipFile;
3742

@@ -44,6 +49,7 @@
4449
import org.eclipse.jdt.core.JavaCore;
4550
import org.eclipse.jdt.launching.IVMInstall;
4651
import org.eclipse.jdt.launching.JavaRuntime;
52+
import org.eclipse.jdt.launching.LibraryLocation;
4753
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
4854
import org.eclipse.osgi.service.resolver.BundleDescription;
4955
import org.eclipse.osgi.service.resolver.ExportPackageDescription;
@@ -388,7 +394,6 @@ public void resolveState() {
388394

389395
// initialize profileManager and get the JRE profiles
390396
String[] javaProfiles = getJavaProfiles();
391-
String systemPackages = null;
392397
String ee = null;
393398

394399
for (Config aConfig : configs) {
@@ -435,7 +440,8 @@ public void resolveState() {
435440
if (profileProps != null) {
436441
String profileName = profileProps.getProperty(ProfileManager.PROFILE_NAME);
437442
if (AbstractScriptGenerator.getImmutableAntProperty(profileName) != null || (j == 0 && !added)) {
438-
systemPackages = profileProps.getProperty(ProfileManager.SYSTEM_PACKAGES);
443+
IExecutionEnvironment env = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(javaProfiles[j]);
444+
String systemPackages = getSystemPackages(env, profileProps);
439445
ee = profileProps.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
440446

441447
prop = new Hashtable<>();
@@ -459,7 +465,7 @@ public void resolveState() {
459465
for (String execEnvID : eeJava10AndBeyond) {
460466
prop = new Hashtable<>();
461467
IExecutionEnvironment env = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(execEnvID);
462-
systemPackages = querySystemPackages(env);
468+
String systemPackages = querySystemPackages(env, null);
463469
String currentEE = previousEE + "," + execEnvID; //$NON-NLS-1$
464470
if (systemPackages == null) {
465471
previousEE = currentEE;
@@ -480,13 +486,178 @@ public void resolveState() {
480486
}
481487
}
482488

483-
public static String querySystemPackages(IExecutionEnvironment environment) {
484-
// Copy of org.eclipse.pde.internal.core.TargetPlatformHelper.querySystemPackages()
485-
IVMInstall vm = bestVmInstallFor(environment);
486-
if (vm == null || !JavaRuntime.isModularJava(vm)) {
489+
public static String getSystemPackages(IExecutionEnvironment environment, Properties profileProperties) {
490+
// The pre-defined lists of system-packages are incomplete. Always overwrite, if we have a more up-to-date one.
491+
String systemPackages = querySystemPackages(environment, profileProperties);
492+
if (systemPackages == null && profileProperties != null) {
493+
// Unable to compute system-packages, probably OSGi specific EE, use the those its profile
494+
systemPackages = profileProperties.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES);
495+
}
496+
return systemPackages;
497+
}
498+
499+
private static final Pattern COMMA = Pattern.compile(","); //$NON-NLS-1$
500+
501+
public static String querySystemPackages(IExecutionEnvironment environment, Properties preJava9ProfileProperties) {
502+
if (environment == null) {
503+
return null;
504+
}
505+
String eeId = environment.getId();
506+
Integer releaseVersion = readJavaReleaseVersion(eeId);
507+
if (releaseVersion == null) {
487508
return null;
488509
}
489-
String release = environment.getProfileProperties().getProperty(JavaCore.COMPILER_COMPLIANCE);
510+
Collection<String> systemPackages;
511+
if (releaseVersion <= 8) {
512+
IVMInstall eeVM = bestVmInstallFor(environment, vms -> null); // Use selected VM or a perfect match
513+
if (eeVM != null) {
514+
// In case a VM is selected for an EE, query that VM and use its system-packages
515+
systemPackages = querySystemPackages(eeVM, null);
516+
} else {
517+
// No VM selected for the non-modular EE:
518+
// Compose list of available system-packages from the java.* packages in the predefined profiles in o.e.osgi respectively the hard-coded lists of java-packages in this class
519+
// plus the non-java packages of this workspace's default VM.
520+
// The reasoning for this is, that the OSGi standard only requires the java.* packages of an EE to be present, everything else is optional.
521+
// Therefore the Workspaces default VM (which can also be set as target VM in the active target-definition) is the best guess for them.
522+
// See also OSGi 8.0 specification chapter 3.4 Execution Environment
523+
524+
List<String> javaPackages = PRE_JAVA_9_SYSTEM_PACKAGES.get(eeId);
525+
if (javaPackages == null) {
526+
String profileSystemPackages = preJava9ProfileProperties.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES, ""); //$NON-NLS-1$
527+
if (profileSystemPackages.isBlank()) {
528+
return null;
529+
}
530+
javaPackages = COMMA.splitAsStream(profileSystemPackages).filter(p -> p.startsWith("java.")).toList(); //$NON-NLS-1$
531+
}
532+
IVMInstall targetVM = JavaRuntime.getDefaultVMInstall(); // Set by the Target-Definition if specified there
533+
Collection<String> targetVMSystemPackages = querySystemPackages(targetVM, null);
534+
if (targetVMSystemPackages == null) {
535+
return null;
536+
}
537+
Stream<String> targetVMNonJavaPackages = targetVMSystemPackages.stream().filter(p -> !p.startsWith("java.")); //$NON-NLS-1$
538+
539+
systemPackages = Stream.concat(javaPackages.stream(), targetVMNonJavaPackages).sorted().toList();
540+
}
541+
} else {
542+
IVMInstall vm = bestVmInstallFor(environment, vms -> vms[0]);
543+
if (vm == null) {
544+
return null;
545+
}
546+
systemPackages = querySystemPackages(vm, environment);
547+
}
548+
return String.join(",", systemPackages); //$NON-NLS-1$
549+
}
550+
551+
@SuppressWarnings("nls")
552+
private static Integer readJavaReleaseVersion(String eeId) {
553+
if (eeId.startsWith("JavaSE-")) { //$NON-NLS-1$
554+
try {
555+
return Integer.parseInt(eeId.substring("JavaSE-".length())); //$NON-NLS-1$
556+
} catch (NumberFormatException e) { // Another EE
557+
}
558+
}
559+
return switch (eeId) {
560+
// There is no EE for Java 1.0 in OSGi
561+
case "JRE-1.1" -> 1;
562+
case "J2SE-1.2" -> 2;
563+
case "J2SE-1.3" -> 3;
564+
case "J2SE-1.4" -> 4;
565+
case "J2SE-1.5" -> 5;
566+
case "JavaSE-1.6" -> 6;
567+
case "JavaSE-1.7" -> 7;
568+
case "JavaSE-1.8" -> 8;
569+
default -> null;
570+
};
571+
}
572+
573+
// Old JDKs can for example be obtained from https://www.oracle.com/java/technologies/downloads/archive/
574+
@SuppressWarnings("nls")
575+
private static final Map<String, List<String>> PRE_JAVA_9_SYSTEM_PACKAGES = Map.of(//
576+
"JRE-1.1", List.of("java.applet", //
577+
"java.awt", //
578+
"java.awt.datatransfer", //
579+
"java.awt.event", //
580+
"java.awt.image", //
581+
"java.awt.peer", //
582+
"java.beans", //
583+
"java.io", //
584+
"java.lang", //
585+
"java.lang.reflect", //
586+
"java.math", //
587+
"java.net", //
588+
"java.rmi", //
589+
"java.rmi.dgc", //
590+
"java.rmi.registry", //
591+
"java.rmi.server", //
592+
"java.security", //
593+
"java.security.acl", //
594+
"java.security.interfaces", //
595+
"java.sql", //
596+
"java.text", //
597+
"java.text.resources", //
598+
"java.util", //
599+
"java.util.zip"),
600+
"J2SE-1.2", List.of("java.applet", //
601+
"java.awt", //
602+
"java.awt.color", //
603+
"java.awt.datatransfer", //
604+
"java.awt.dnd", //
605+
"java.awt.dnd.peer", //
606+
"java.awt.event", //
607+
"java.awt.font", //
608+
"java.awt.geom", //
609+
"java.awt.im", //
610+
"java.awt.image", //
611+
"java.awt.image.renderable", //
612+
"java.awt.peer", //
613+
"java.awt.print", //
614+
"java.awt.resources", //
615+
"java.beans", //
616+
"java.beans.beancontext", //
617+
"java.io", //
618+
"java.lang", //
619+
"java.lang.ref", //
620+
"java.lang.reflect", //
621+
"java.math", //
622+
"java.net", //
623+
"java.rmi", //
624+
"java.rmi.activation", //
625+
"java.rmi.dgc", //
626+
"java.rmi.registry", //
627+
"java.rmi.server", //
628+
"java.security", //
629+
"java.security.acl", //
630+
"java.security.cert", //
631+
"java.security.interfaces", //
632+
"java.security.spec", //
633+
"java.sql", //
634+
"java.text", //
635+
"java.text.resources", //
636+
"java.util", //
637+
"java.util.jar", //
638+
"java.util.zip"));
639+
640+
private static Collection<String> querySystemPackages(IVMInstall vm, IExecutionEnvironment environment) {
641+
if (!JavaRuntime.isModularJava(vm)) {
642+
Set<String> classFileDirectories = new HashSet<>();
643+
for (LibraryLocation libLocation : JavaRuntime.getLibraryLocations(vm)) {
644+
IPath path = libLocation.getSystemLibraryPath();
645+
if (path != null) {
646+
try (ZipFile zip = new ZipFile(path.toFile())) {
647+
// Collect names of all directories that contain a .class file
648+
zip.stream().filter(e -> !e.isDirectory()).map(ZipEntry::getName) //
649+
.filter(n -> n.endsWith(".class")) //$NON-NLS-1$
650+
.map(n -> n.substring(0, n.lastIndexOf('/'))) //
651+
.forEach(classFileDirectories::add);
652+
} catch (IOException e) {
653+
ILog.get().error("Failed to read packages in JVM library for " + vm + ", at " + path, e); //$NON-NLS-1$ //$NON-NLS-2$
654+
}
655+
}
656+
}
657+
return classFileDirectories.stream().map(n -> n.replace('/', '.')).sorted().toList();
658+
}
659+
660+
String release = environment != null ? environment.getProfileProperties().getProperty(JavaCore.COMPILER_COMPLIANCE) : null;
490661
try {
491662
Collection<String> packages = new TreeSet<>();
492663
String jrtPath = "lib/" + org.eclipse.jdt.internal.compiler.util.JRTUtil.JRT_FS_JAR; //$NON-NLS-1$
@@ -503,17 +674,14 @@ public static String querySystemPackages(IExecutionEnvironment environment) {
503674
}
504675
}
505676
}
506-
return String.join(",", packages); //$NON-NLS-1$
677+
return packages;
507678
} catch (CoreException e) {
508-
ILog.of(PDEState.class).log(Status.error("failed to read system packages for " + environment, e)); //$NON-NLS-1$
679+
ILog.of(PDEState.class).log(Status.error("Failed to read system packages for " + environment, e)); //$NON-NLS-1$
509680
}
510681
return null;
511682
}
512683

513-
private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment) {
514-
if (environment == null) {
515-
return null;
516-
}
684+
private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment, Function<IVMInstall[], IVMInstall> nonStrictDefaultSelector) {
517685
IVMInstall defaultVM = environment.getDefaultVM();
518686
if (defaultVM != null) {
519687
return defaultVM;
@@ -522,12 +690,8 @@ private static IVMInstall bestVmInstallFor(IExecutionEnvironment environment) {
522690
if (compatible.length == 0) {
523691
return null;
524692
}
525-
for (IVMInstall vm : compatible) {
526-
if (environment.isStrictlyCompatible(vm)) {
527-
return vm;
528-
}
529-
}
530-
return compatible[0];
693+
Optional<IVMInstall> vm = Arrays.stream(compatible).filter(environment::isStrictlyCompatible).findFirst();
694+
return vm.isPresent() ? vm.get() : nonStrictDefaultSelector.apply(compatible);
531695
}
532696

533697
public State getState() {

0 commit comments

Comments
 (0)