Skip to content

Commit 6cc071a

Browse files
Automatically register VMInstalls for the JDKs installed on the local machine (#3251)
* Automatically register VMInstalls for the JDKs installed on the local machine * disable jdt vm detection job by default Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>
1 parent 5d224a5 commit 6cc071a

9 files changed

Lines changed: 122 additions & 40 deletions

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@
15451545
"fs-extra": "^8.1.0",
15461546
"glob": "^7.1.3",
15471547
"htmlparser2": "6.0.1",
1548-
"jdk-utils": "^0.4.4",
1548+
"jdk-utils": "^0.5.0",
15491549
"react": "^17.0.2",
15501550
"react-dom": "^17.0.2",
15511551
"semver": "^7.5.2",

src/extension.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
155155
initializationOptions: {
156156
bundles: collectJavaExtensions(extensions.all),
157157
workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null,
158-
settings: { java: getJavaConfig(requirements.java_home) },
158+
settings: { java: await getJavaConfig(requirements.java_home) },
159159
extendedClientCapabilities: {
160160
classFileContentsSupport: true,
161161
overrideMethodsPromptSupport: true,
@@ -184,7 +184,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
184184
didChangeConfiguration: async () => {
185185
await standardClient.getClient().sendNotification(DidChangeConfigurationNotification.type, {
186186
settings: {
187-
java: getJavaConfig(requirements.java_home),
187+
java: await getJavaConfig(requirements.java_home),
188188
}
189189
});
190190
}
@@ -267,7 +267,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
267267
// the promise is resolved
268268
// no need to pass `resolve` into any code past this point,
269269
// since `resolve` is a no-op from now on
270-
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, getJavaConfig(requirements.java_home), context, true);
270+
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, context, true);
271271
if (requireSyntaxServer) {
272272
if (process.env['SYNTAXLS_CLIENT_PORT']) {
273273
syntaxClient.initialize(requirements, clientOptions);

src/javaServerStarter.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const HEAP_DUMP = '-XX:+HeapDumpOnOutOfMemoryError';
3434
const DEPENDENCY_COLLECTOR_IMPL= '-Daether.dependencyCollector.impl=';
3535
const DEPENDENCY_COLLECTOR_IMPL_BF= 'bf';
3636

37-
export function prepareExecutable(requirements: RequirementsData, workspacePath, javaConfig, context: ExtensionContext, isSyntaxServer: boolean): Executable {
37+
export function prepareExecutable(requirements: RequirementsData, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): Executable {
3838
const executable: Executable = Object.create(null);
3939
const options: ExecutableOptions = Object.create(null);
4040
options.env = Object.assign({ syntaxserver : isSyntaxServer }, process.env);
@@ -47,7 +47,7 @@ export function prepareExecutable(requirements: RequirementsData, workspacePath,
4747
}
4848
executable.options = options;
4949
executable.command = path.resolve(`${requirements.tooling_jre}/bin/java`);
50-
executable.args = prepareParams(requirements, javaConfig, workspacePath, context, isSyntaxServer);
50+
executable.args = prepareParams(requirements, workspacePath, context, isSyntaxServer);
5151
logger.info(`Starting Java server with: ${executable.command} ${executable.args.join(' ')}`);
5252
return executable;
5353
}
@@ -68,7 +68,7 @@ export function awaitServerConnection(port): Thenable<StreamInfo> {
6868
});
6969
}
7070

71-
function prepareParams(requirements: RequirementsData, javaConfiguration, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): string[] {
71+
function prepareParams(requirements: RequirementsData, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): string[] {
7272
const params: string[] = [];
7373
if (DEBUG) {
7474
const port = isSyntaxServer ? 1045 : 1044;
@@ -117,6 +117,9 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp
117117
} else {
118118
vmargs = '';
119119
}
120+
if (vmargs.indexOf('-DDetectVMInstallationsJob.disabled=') < 0) {
121+
params.push('-DDetectVMInstallationsJob.disabled=true');
122+
}
120123
const encodingKey = '-Dfile.encoding=';
121124
if (vmargs.indexOf(encodingKey) < 0) {
122125
params.push(encodingKey + getJavaEncoding());

src/jdkUtils.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
'use strict';
2+
3+
import { IJavaRuntime, findRuntimes, getSources } from 'jdk-utils';
4+
5+
let cachedJdks: IJavaRuntime[];
6+
7+
export async function listJdks(force?: boolean): Promise<IJavaRuntime[]> {
8+
if (force || !cachedJdks) {
9+
cachedJdks = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
10+
}
11+
12+
return [].concat(cachedJdks);
13+
}
14+
15+
/**
16+
* Sort by source where JDk is located.
17+
* The order is:
18+
* 1. JDK_HOME, JAVA_HOME, PATH
19+
* 2. JDK manager such as SDKMAN, jEnv, jabba, asdf
20+
* 3. Common places such as /usr/lib/jvm
21+
* 4. Others
22+
*/
23+
export function sortJdksBySource(jdks: IJavaRuntime[]) {
24+
const rankedJdks = jdks as Array<IJavaRuntime & { rank: number }>;
25+
const env: string[] = ["JDK_HOME", "JAVA_HOME", "PATH"];
26+
const jdkManagers: string[] = ["SDKMAN", "jEnv", "jabba", "asdf"];
27+
for (const jdk of rankedJdks) {
28+
const detectedSources: string[] = getSources(jdk);
29+
for (const [index, source] of env.entries()) {
30+
if (detectedSources.includes(source)) {
31+
jdk.rank = index; // jdk from environment variables
32+
break;
33+
}
34+
}
35+
36+
if (jdk.rank) {
37+
continue;
38+
}
39+
40+
const fromManager: boolean = detectedSources.some(source => jdkManagers.includes(source));
41+
if (fromManager) {
42+
jdk.rank = env.length + 1; // jdk from the jdk managers such as SDKMAN
43+
} else if (!detectedSources.length){
44+
jdk.rank = env.length + 2; // jdk from common places
45+
} else {
46+
jdk.rank = env.length + 3; // jdk from other source such as ~/.gradle/jdks
47+
}
48+
}
49+
rankedJdks.sort((a, b) => a.rank - b.rank);
50+
}
51+
52+
/**
53+
* Sort by major version in descend order.
54+
*/
55+
export function sortJdksByVersion(jdks: IJavaRuntime[]) {
56+
jdks.sort((a, b) => (b.version?.major ?? 0) - (a.version?.major ?? 0));
57+
}

src/requirements.ts

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import * as expandHomeDir from 'expand-home-dir';
44
import * as fse from 'fs-extra';
5-
import { findRuntimes, getRuntime, getSources, IJavaRuntime, JAVAC_FILENAME, JAVA_FILENAME } from 'jdk-utils';
5+
import { getRuntime, getSources, JAVAC_FILENAME, JAVA_FILENAME } from 'jdk-utils';
66
import * as path from 'path';
77
import { env, ExtensionContext, Uri, window, workspace } from 'vscode';
88
import { Commands } from './commands';
99
import { logger } from './log';
1010
import { checkJavaPreferences } from './settings';
11+
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';
1112

1213
const REQUIRED_JDK_VERSION = 17;
1314
/* eslint-disable @typescript-eslint/naming-convention */
@@ -70,7 +71,7 @@ export async function resolveRequirements(context: ExtensionContext): Promise<Re
7071
}
7172

7273
// search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
73-
const javaRuntimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
74+
const javaRuntimes = await listJdks();
7475
if (!toolingJre) { // universal version
7576
// as latest version as possible.
7677
sortJdksByVersion(javaRuntimes);
@@ -159,27 +160,6 @@ async function findDefaultRuntimeFromSettings(): Promise<string | undefined> {
159160
return undefined;
160161
}
161162

162-
export function sortJdksBySource(jdks: IJavaRuntime[]) {
163-
const rankedJdks = jdks as Array<IJavaRuntime & { rank: number }>;
164-
const sources = ["JDK_HOME", "JAVA_HOME", "PATH"];
165-
for (const [index, source] of sources.entries()) {
166-
for (const jdk of rankedJdks) {
167-
if (jdk.rank === undefined && getSources(jdk).includes(source)) {
168-
jdk.rank = index;
169-
}
170-
}
171-
}
172-
rankedJdks.filter(jdk => jdk.rank === undefined).forEach(jdk => jdk.rank = sources.length);
173-
rankedJdks.sort((a, b) => a.rank - b.rank);
174-
}
175-
176-
/**
177-
* Sort by major version in descend order.
178-
*/
179-
export function sortJdksByVersion(jdks: IJavaRuntime[]) {
180-
jdks.sort((a, b) => (b.version?.major ?? 0) - (a.version?.major ?? 0));
181-
}
182-
183163
export function parseMajorVersion(version: string): number {
184164
if (!version) {
185165
return 0;

src/standardLanguageClient.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
'use strict';
22

3-
import * as fse from 'fs-extra';
4-
import { findRuntimes } from "jdk-utils";
53
import * as net from 'net';
64
import * as path from 'path';
75
import { CancellationToken, CodeActionKind, commands, ConfigurationTarget, DocumentSelector, EventEmitter, ExtensionContext, extensions, languages, Location, ProgressLocation, TextEditor, Uri, ViewColumn, window, workspace } from "vscode";
@@ -24,7 +22,7 @@ import { collectBuildFilePattern, onExtensionChange } from "./plugin";
2422
import { pomCodeActionMetadata, PomCodeActionProvider } from "./pom/pomCodeActionProvider";
2523
import { ActionableNotification, BuildProjectParams, BuildProjectRequest, CompileWorkspaceRequest, CompileWorkspaceStatus, EventNotification, EventType, ExecuteClientCommandRequest, FeatureStatus, FindLinks, GradleCompatibilityInfo, LinkLocation, ProgressKind, ProgressNotification, ServerNotification, SourceAttachmentAttribute, SourceAttachmentRequest, SourceAttachmentResult, SourceInvalidatedEvent, StatusNotification, UpgradeGradleWrapperInfo } from "./protocol";
2624
import * as refactorAction from './refactorAction';
27-
import { getJdkUrl, RequirementsData, sortJdksBySource, sortJdksByVersion } from "./requirements";
25+
import { getJdkUrl, RequirementsData } from "./requirements";
2826
import { serverStatus, ServerStatusKind } from "./serverStatus";
2927
import { serverStatusBarProvider } from "./serverStatusBarProvider";
3028
import { activationProgressNotification, serverTaskPresenter } from "./serverTaskPresenter";
@@ -41,6 +39,7 @@ import { Telemetry } from "./telemetry";
4139
import { TelemetryEvent } from "@redhat-developer/vscode-redhat-telemetry/lib";
4240
import { registerDocumentValidationListener } from './diagnostic';
4341
import { registerSmartSemicolonDetection } from './smartSemicolonDetection';
42+
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';
4443

4544
const extensionName = 'Language Support for Java';
4645
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
@@ -91,7 +90,7 @@ export class StandardLanguageClient {
9190
if (!port) {
9291
const lsPort = process.env['JDTLS_CLIENT_PORT'];
9392
if (!lsPort) {
94-
serverOptions = prepareExecutable(requirements, workspacePath, getJavaConfig(requirements.java_home), context, false);
93+
serverOptions = prepareExecutable(requirements, workspacePath, context, false);
9594
} else {
9695
serverOptions = () => {
9796
const socket = net.connect(lsPort);
@@ -217,7 +216,7 @@ export class StandardLanguageClient {
217216
const options: string[] = [];
218217
const info = notification.data as GradleCompatibilityInfo;
219218
const highestJavaVersion = Number(info.highestJavaVersion);
220-
let runtimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
219+
let runtimes = await listJdks(true);
221220
runtimes = runtimes.filter(runtime => {
222221
return runtime.version.major <= highestJavaVersion;
223222
});

src/syntaxLanguageClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class SyntaxLanguageClient {
2828
didChangeConfiguration: async () => {
2929
await this.languageClient.sendNotification(DidChangeConfigurationNotification.type, {
3030
settings: {
31-
java: getJavaConfig(requirements.java_home),
31+
java: await getJavaConfig(requirements.java_home),
3232
}
3333
});
3434
}

src/utils.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as fs from 'fs';
44
import * as path from 'path';
55
import { workspace, WorkspaceConfiguration, commands, Uri, version } from 'vscode';
66
import { Commands } from './commands';
7+
import { IJavaRuntime } from 'jdk-utils';
8+
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';
79

810
export function getJavaConfiguration(): WorkspaceConfiguration {
911
return workspace.getConfiguration('java');
@@ -176,7 +178,7 @@ function getDirectoriesByBuildFile(inclusions: string[], exclusions: string[], f
176178
}
177179

178180

179-
export function getJavaConfig(javaHome: string) {
181+
export async function getJavaConfig(javaHome: string) {
180182
const origConfig = getJavaConfiguration();
181183
const javaConfig = JSON.parse(JSON.stringify(origConfig));
182184
javaConfig.home = javaHome;
@@ -215,5 +217,46 @@ export function getJavaConfig(javaHome: string) {
215217
}
216218

217219
javaConfig.telemetry = { enabled: workspace.getConfiguration('redhat.telemetry').get('enabled', false) };
220+
const userConfiguredJREs: any[] = javaConfig.configuration.runtimes;
221+
javaConfig.configuration.runtimes = await addAutoDetectedJdks(userConfiguredJREs);
218222
return javaConfig;
219223
}
224+
225+
async function addAutoDetectedJdks(configuredJREs: any[]): Promise<any[]> {
226+
// search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
227+
const autoDetectedJREs: IJavaRuntime[] = await listJdks();
228+
sortJdksByVersion(autoDetectedJREs);
229+
sortJdksBySource(autoDetectedJREs);
230+
const addedJreNames: Set<string> = new Set<string>();
231+
for (const jre of configuredJREs) {
232+
if (jre.name) {
233+
addedJreNames.add(jre.name);
234+
}
235+
}
236+
for (const jre of autoDetectedJREs) {
237+
const majorVersion: number = jre.version?.major ?? 0;
238+
if (!majorVersion) {
239+
continue;
240+
}
241+
242+
let jreName: string = `JavaSE-${majorVersion}`;
243+
if (majorVersion <= 5) {
244+
jreName = `J2SE-1.${majorVersion}`;
245+
} else if (majorVersion <= 8) {
246+
jreName = `JavaSE-1.${majorVersion}`;
247+
}
248+
249+
if (addedJreNames.has(jreName)) {
250+
continue;
251+
}
252+
253+
configuredJREs.push({
254+
name: jreName,
255+
path: jre.homedir,
256+
});
257+
258+
addedJreNames.add(jreName);
259+
}
260+
261+
return configuredJREs;
262+
}

0 commit comments

Comments
 (0)