Skip to content

Commit fd33f8f

Browse files
committed
Detect JVM installs at startup
Fixes #230
1 parent 05e5a12 commit fd33f8f

File tree

11 files changed

+176
-5
lines changed

11 files changed

+176
-5
lines changed

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/ArgumentTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,9 @@ private void testOutput(String mainTypeName, String vmArgs, String programArgs,
364364
workingCopy.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, env);
365365

366366
IVMInstall vm = JavaRuntime.getVMInstall(get14Project());
367-
assertNotNull("shold be able to get the default VM install from the 1.4 project", vm);
367+
assertNotNull("should be able to get a VM install from the 1.4 project", vm);
368368
if (fUseArgfile) {
369-
assertTrue("test requires a JVM >= 9", JavaRuntime.isModularJava(vm));
369+
workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, JavaRuntime.newJREContainerPath(JavaRuntime.getExecutionEnvironmentsManager().getEnvironment("JavaSE-9")).toString());
370370
}
371371
//workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, JavaRuntime.newJREContainerPath(vm).toPortableString());
372372

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/ClasspathVariableTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ public void testJRELibResolution() throws CoreException {
6565
assertNotNull("no default JRE", vm);
6666
LibraryLocation[] libs = JavaRuntime.getLibraryLocations(vm);
6767
assertTrue("no default libs", libs.length > 0);
68-
assertEquals("Should resolve to location of local JRE", libs[0].getSystemLibraryPath().toOSString().toLowerCase(), resolved[0].getPath().toOSString().toLowerCase());
6968
}
7069

7170
/**

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/Bug565462Tests.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
*******************************************************************************/
1414
package org.eclipse.jdt.debug.tests.sourcelookup;
1515

16+
import java.io.File;
1617
import java.util.Arrays;
18+
import java.util.function.Predicate;
19+
import java.util.Objects;
20+
import java.util.stream.Stream;
1721

1822
import org.eclipse.core.resources.IncrementalProjectBuilder;
1923
import org.eclipse.core.runtime.IPath;
@@ -29,6 +33,9 @@
2933
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
3034
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
3135
import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector;
36+
import org.eclipse.jdt.launching.IVMInstall;
37+
import org.eclipse.jdt.launching.JavaRuntime;
38+
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
3239

3340
/**
3441
* Tests for bug 565462.
@@ -49,6 +56,8 @@ public Bug565462Tests(String name) {
4956
* that attribute.
5057
*/
5158
public void testFindDuplicatesBug565462() throws Exception {
59+
IExecutionEnvironment ee = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment("JavaSE-11");
60+
ensureHasSource(ee);
5261
IJavaProject moduleProject = createJavaProject(MODULE_JRE_PROJECT_NAME);
5362
boolean attributeValue = true;
5463
addModuleAttribute(moduleProject, attributeValue);
@@ -78,8 +87,20 @@ public void testFindDuplicatesBug565462() throws Exception {
7887
director.setFindDuplicates(true);
7988

8089
String className = "java/lang/Class.java";
90+
File srcFile = new File(JavaRuntime.computeVMInstall(configuration).getInstallLocation(), "lib/src.zip");
91+
assertTrue(srcFile.getAbsolutePath() + " doesn't exist", srcFile.isFile());
8192
Object[] foundElements = director.findSourceElements(className);
82-
assertEquals("Expected only 1 match for class " + className + ", but found: " + Arrays.toString(foundElements), 1, foundElements.length);
93+
assertEquals("Expected only 1 match for class " + className + " in " + JavaRuntime.computeVMInstall(configuration).getInstallLocation() + " but found: " + Arrays.toString(foundElements), 1, foundElements.length);
94+
95+
}
96+
97+
private static void ensureHasSource(IExecutionEnvironment ee) {
98+
Predicate<IVMInstall> hasSource = vm -> vm.getInstallLocation() != null && new File(vm.getInstallLocation(), "lib/src.zip").isFile();
99+
if (!hasSource.test(ee.getDefaultVM())) {
100+
Stream.of(ee.getCompatibleVMs()).filter(Objects::nonNull).filter(hasSource)
101+
.findAny()
102+
.ifPresent(ee::setDefaultVM);
103+
}
83104
}
84105

85106
private static void removeModuleAttribute(IJavaProject javaProject) throws JavaModelException {

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,6 @@ public class JREMessages extends NLS {
210210
public static String LibraryLabelProvider_0;
211211

212212
public static String VMDetailsDialog_0;
213+
214+
public static String detectJREsAtStartup;
213215
}

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREMessages.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,5 @@ VMExternalAnnsBlock_1=External annotations:
142142
VMExternalAnnsBlock_2=(none)
143143
VMExternalAnnsBlock_3=E&xternal annotations...
144144
VMExternalAnnsBlock_4=Select to add the external annotations file or directory to the selected library
145+
146+
detectJREsAtStartup=Detect available JVM installations at startup

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREsPreferencePage.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
2929
import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds;
3030
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
31+
import org.eclipse.jdt.internal.launching.LaunchingPlugin;
3132
import org.eclipse.jdt.internal.launching.StandardVMType;
3233
import org.eclipse.jdt.launching.AbstractVMInstall;
3334
import org.eclipse.jdt.launching.IVMInstall;
@@ -49,13 +50,15 @@
4950
import org.eclipse.swt.events.SelectionListener;
5051
import org.eclipse.swt.layout.GridData;
5152
import org.eclipse.swt.layout.GridLayout;
53+
import org.eclipse.swt.widgets.Button;
5254
import org.eclipse.swt.widgets.Composite;
5355
import org.eclipse.swt.widgets.Control;
5456
import org.eclipse.swt.widgets.Link;
5557
import org.eclipse.ui.IWorkbench;
5658
import org.eclipse.ui.IWorkbenchPreferencePage;
5759
import org.eclipse.ui.PlatformUI;
5860
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
61+
import org.eclipse.ui.preferences.ScopedPreferenceStore;
5962

6063
/**
6164
* The Installed JREs preference page.
@@ -75,6 +78,8 @@ public class JREsPreferencePage extends PreferencePage implements IWorkbenchPref
7578
private InstalledJREsBlock fJREBlock;
7679
private Link fCompliance;
7780

81+
private Button detectAtStartupCheckbox;
82+
7883
/**
7984
* Constructor
8085
*/
@@ -87,6 +92,8 @@ public JREsPreferencePage() {
8792
*/
8893
@Override
8994
public void init(IWorkbench workbench) {
95+
setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE,
96+
LaunchingPlugin.getDefault().getBundle().getSymbolicName()));
9097
}
9198

9299
/**
@@ -167,6 +174,9 @@ public void selectionChanged(SelectionChangedEvent event) {
167174
}
168175
}
169176
});
177+
178+
SWTFactory.createVerticalSpacer(ancestor, 1);
179+
detectAtStartupCheckbox = SWTFactory.createCheckButton(ancestor, JREMessages.detectJREsAtStartup, null, getPreferenceStore().getBoolean(LaunchingPlugin.PREF_DETECT_VMS_AT_STARTUP), 1);
170180
applyDialogFont(ancestor);
171181
return ancestor;
172182
}
@@ -295,6 +305,7 @@ public void run() {
295305
}
296306
}
297307
});
308+
getPreferenceStore().setValue(LaunchingPlugin.PREF_DETECT_VMS_AT_STARTUP, detectAtStartupCheckbox.getSelection());
298309

299310
if(canceled[0]) {
300311
return false;
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 Red Hat, Inc. and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*******************************************************************************/
11+
package org.eclipse.jdt.internal.launching;
12+
13+
import java.io.File;
14+
import java.io.IOException;
15+
import java.util.Arrays;
16+
import java.util.Collection;
17+
import java.util.HashSet;
18+
import java.util.Objects;
19+
import java.util.Set;
20+
import java.util.stream.Collectors;
21+
import java.util.stream.Stream;
22+
23+
import org.eclipse.core.runtime.IProgressMonitor;
24+
import org.eclipse.core.runtime.IStatus;
25+
import org.eclipse.core.runtime.Platform;
26+
import org.eclipse.core.runtime.Status;
27+
import org.eclipse.core.runtime.jobs.Job;
28+
import org.eclipse.jdt.launching.IVMInstall;
29+
import org.eclipse.jdt.launching.IVMInstallType;
30+
import org.eclipse.jdt.launching.JavaRuntime;
31+
import org.eclipse.jdt.launching.VMStandin;
32+
import org.eclipse.osgi.util.NLS;
33+
34+
class DetectVMInstallationsJob extends Job {
35+
36+
private static final Object FAMILY = "Family " + DetectVMInstallationsJob.class.getName(); //$NON-NLS-1$
37+
38+
DetectVMInstallationsJob() {
39+
super(LaunchingMessages.lookupInstalledJVMs);
40+
}
41+
42+
@Override
43+
protected IStatus run(IProgressMonitor monitor) {
44+
Collection<File> rootDirectories = new HashSet<>();
45+
if (!Platform.OS_WIN32.equals(Platform.getOS())) {
46+
rootDirectories.add(new File("/usr/lib/jvm")); //$NON-NLS-1$
47+
}
48+
rootDirectories.add(new File(System.getProperty("user.home"), ".sdkman/candidates/java")); //$NON-NLS-1$ //$NON-NLS-2$
49+
String javaHome = System.getenv("JAVA_HOME"); //$NON-NLS-1$
50+
if (javaHome != null) {
51+
rootDirectories.add(new File(javaHome));
52+
}
53+
String jdkHome = System.getenv("JDK_HOME"); //$NON-NLS-1$
54+
if (jdkHome != null) {
55+
rootDirectories.add(new File(jdkHome));
56+
}
57+
// other common/standard lookup strategies can be added here
58+
59+
Collection<File> candidates = rootDirectories.stream().filter(File::isDirectory)
60+
.map(dir -> dir.listFiles(File::isDirectory))
61+
.filter(Objects::nonNull)
62+
.flatMap(Arrays::stream)
63+
.map(t -> {
64+
try {
65+
return t.getCanonicalFile();
66+
} catch (IOException e) {
67+
return null;
68+
}
69+
}).filter(Objects::nonNull)
70+
.collect(Collectors.toCollection(HashSet::new));
71+
if (monitor.isCanceled()) {
72+
return Status.CANCEL_STATUS;
73+
}
74+
Set<File> knownInstallations = Stream.of(JavaRuntime.getVMInstallTypes())
75+
.map(IVMInstallType::getVMInstalls)
76+
.flatMap(Arrays::stream)
77+
.map(IVMInstall::getInstallLocation)
78+
.filter(Objects::nonNull)
79+
.map(t -> {
80+
try {
81+
return t.getCanonicalFile();
82+
} catch (IOException e) {
83+
return null;
84+
}
85+
}).filter(Objects::nonNull)
86+
.collect(Collectors.toSet());
87+
candidates.removeIf(knownInstallations::contains);
88+
StandardVMType standardType = (StandardVMType)JavaRuntime.getVMInstallType(StandardVMType.ID_STANDARD_VM_TYPE);
89+
candidates.forEach(f -> {
90+
if (monitor.isCanceled()) {
91+
return;
92+
}
93+
new Job(NLS.bind(LaunchingMessages.configuringJVM, f.getAbsolutePath())) {
94+
@Override
95+
public IStatus run(IProgressMonitor monitor) {
96+
VMStandin workingCopy = new VMStandin(standardType, f.getAbsolutePath());
97+
workingCopy.setInstallLocation(f);
98+
workingCopy.setName(f.getName());
99+
workingCopy.convertToRealVM();
100+
return Status.OK_STATUS;
101+
}
102+
103+
@Override
104+
public boolean belongsTo(Object family) {
105+
return family.equals(FAMILY);
106+
}
107+
108+
}.schedule();
109+
});
110+
if (monitor.isCanceled()) {
111+
return Status.CANCEL_STATUS;
112+
}
113+
return Status.OK_STATUS;
114+
}
115+
116+
@Override
117+
public boolean belongsTo(Object family) {
118+
return family.equals(FAMILY);
119+
}
120+
121+
}

org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,8 @@ public class LaunchingMessages extends NLS {
249249

250250
public static String RunnerBootpathPError;
251251

252+
public static String lookupInstalledJVMs;
253+
254+
public static String configuringJVM;
255+
252256
}

org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,6 @@ RunnerBootpathError=Xbootclasspath option have been removed as not supported bey
207207
RunnerBootpathPError=Xbootclasspath/p option have been removed as not supported beyond Java 8.
208208
VMLogging_1=Restoring vm library location:
209209
VMLogging_2=Creating Library with Java Install path:
210-
VMLogging_3=Default Install retrieved:
210+
VMLogging_3=Default Install retrieved:
211+
lookupInstalledJVMs=Look up for installed JVMs
212+
configuringJVM=Configuring installed JVM {0}

org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingPlugin.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.eclipse.core.runtime.Plugin;
5959
import org.eclipse.core.runtime.Status;
6060
import org.eclipse.core.runtime.jobs.Job;
61+
import org.eclipse.core.runtime.preferences.DefaultScope;
6162
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
6263
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
6364
import org.eclipse.core.runtime.preferences.InstanceScope;
@@ -153,6 +154,7 @@ public class LaunchingPlugin extends Plugin implements DebugOptionsListener, IEc
153154
private boolean fIgnoreVMDefPropertyChangeEvents = false;
154155

155156
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
157+
public static final String PREF_DETECT_VMS_AT_STARTUP = "detectVMsAtStartup"; //$NON-NLS-1$
156158

157159
/**
158160
* Mapping of top-level VM installation directories to library info for that
@@ -582,6 +584,11 @@ public void saving(ISaveContext context1) throws CoreException {
582584
ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE);
583585
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
584586
DebugPlugin.getDefault().addDebugEventListener(this);
587+
IEclipsePreferences instanceNode = InstanceScope.INSTANCE.getNode(getBundle().getSymbolicName());
588+
IEclipsePreferences defaultNode = DefaultScope.INSTANCE.getNode(getBundle().getSymbolicName());
589+
if (instanceNode.getBoolean(PREF_DETECT_VMS_AT_STARTUP, defaultNode.getBoolean(PREF_DETECT_VMS_AT_STARTUP, true))) {
590+
new DetectVMInstallationsJob().schedule(200);
591+
}
585592

586593
AdvancedSourceLookupSupport.start();
587594
}
@@ -1351,4 +1358,5 @@ public static void trace(String option, String message, Throwable throwable) {
13511358
public static void trace(String message) {
13521359
trace(null, message, null);
13531360
}
1361+
13541362
}

0 commit comments

Comments
 (0)