Skip to content

Commit

Permalink
Automatically register VMInstalls for the JDKs installed on the local…
Browse files Browse the repository at this point in the history
… 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>
  • Loading branch information
testforstephen authored Aug 23, 2023
1 parent 5d224a5 commit 6cc071a
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 40 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1545,7 +1545,7 @@
"fs-extra": "^8.1.0",
"glob": "^7.1.3",
"htmlparser2": "6.0.1",
"jdk-utils": "^0.4.4",
"jdk-utils": "^0.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"semver": "^7.5.2",
Expand Down
6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
initializationOptions: {
bundles: collectJavaExtensions(extensions.all),
workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null,
settings: { java: getJavaConfig(requirements.java_home) },
settings: { java: await getJavaConfig(requirements.java_home) },
extendedClientCapabilities: {
classFileContentsSupport: true,
overrideMethodsPromptSupport: true,
Expand Down Expand Up @@ -184,7 +184,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
didChangeConfiguration: async () => {
await standardClient.getClient().sendNotification(DidChangeConfigurationNotification.type, {
settings: {
java: getJavaConfig(requirements.java_home),
java: await getJavaConfig(requirements.java_home),
}
});
}
Expand Down Expand Up @@ -267,7 +267,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
// the promise is resolved
// no need to pass `resolve` into any code past this point,
// since `resolve` is a no-op from now on
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, getJavaConfig(requirements.java_home), context, true);
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, context, true);
if (requireSyntaxServer) {
if (process.env['SYNTAXLS_CLIENT_PORT']) {
syntaxClient.initialize(requirements, clientOptions);
Expand Down
9 changes: 6 additions & 3 deletions src/javaServerStarter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const HEAP_DUMP = '-XX:+HeapDumpOnOutOfMemoryError';
const DEPENDENCY_COLLECTOR_IMPL= '-Daether.dependencyCollector.impl=';
const DEPENDENCY_COLLECTOR_IMPL_BF= 'bf';

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

function prepareParams(requirements: RequirementsData, javaConfiguration, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): string[] {
function prepareParams(requirements: RequirementsData, workspacePath, context: ExtensionContext, isSyntaxServer: boolean): string[] {
const params: string[] = [];
if (DEBUG) {
const port = isSyntaxServer ? 1045 : 1044;
Expand Down Expand Up @@ -117,6 +117,9 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp
} else {
vmargs = '';
}
if (vmargs.indexOf('-DDetectVMInstallationsJob.disabled=') < 0) {
params.push('-DDetectVMInstallationsJob.disabled=true');
}
const encodingKey = '-Dfile.encoding=';
if (vmargs.indexOf(encodingKey) < 0) {
params.push(encodingKey + getJavaEncoding());
Expand Down
57 changes: 57 additions & 0 deletions src/jdkUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

import { IJavaRuntime, findRuntimes, getSources } from 'jdk-utils';

let cachedJdks: IJavaRuntime[];

export async function listJdks(force?: boolean): Promise<IJavaRuntime[]> {
if (force || !cachedJdks) {
cachedJdks = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
}

return [].concat(cachedJdks);
}

/**
* Sort by source where JDk is located.
* The order is:
* 1. JDK_HOME, JAVA_HOME, PATH
* 2. JDK manager such as SDKMAN, jEnv, jabba, asdf
* 3. Common places such as /usr/lib/jvm
* 4. Others
*/
export function sortJdksBySource(jdks: IJavaRuntime[]) {
const rankedJdks = jdks as Array<IJavaRuntime & { rank: number }>;
const env: string[] = ["JDK_HOME", "JAVA_HOME", "PATH"];
const jdkManagers: string[] = ["SDKMAN", "jEnv", "jabba", "asdf"];
for (const jdk of rankedJdks) {
const detectedSources: string[] = getSources(jdk);
for (const [index, source] of env.entries()) {
if (detectedSources.includes(source)) {
jdk.rank = index; // jdk from environment variables
break;
}
}

if (jdk.rank) {
continue;
}

const fromManager: boolean = detectedSources.some(source => jdkManagers.includes(source));
if (fromManager) {
jdk.rank = env.length + 1; // jdk from the jdk managers such as SDKMAN
} else if (!detectedSources.length){
jdk.rank = env.length + 2; // jdk from common places
} else {
jdk.rank = env.length + 3; // jdk from other source such as ~/.gradle/jdks
}
}
rankedJdks.sort((a, b) => a.rank - b.rank);
}

/**
* Sort by major version in descend order.
*/
export function sortJdksByVersion(jdks: IJavaRuntime[]) {
jdks.sort((a, b) => (b.version?.major ?? 0) - (a.version?.major ?? 0));
}
26 changes: 3 additions & 23 deletions src/requirements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

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

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

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

export function sortJdksBySource(jdks: IJavaRuntime[]) {
const rankedJdks = jdks as Array<IJavaRuntime & { rank: number }>;
const sources = ["JDK_HOME", "JAVA_HOME", "PATH"];
for (const [index, source] of sources.entries()) {
for (const jdk of rankedJdks) {
if (jdk.rank === undefined && getSources(jdk).includes(source)) {
jdk.rank = index;
}
}
}
rankedJdks.filter(jdk => jdk.rank === undefined).forEach(jdk => jdk.rank = sources.length);
rankedJdks.sort((a, b) => a.rank - b.rank);
}

/**
* Sort by major version in descend order.
*/
export function sortJdksByVersion(jdks: IJavaRuntime[]) {
jdks.sort((a, b) => (b.version?.major ?? 0) - (a.version?.major ?? 0));
}

export function parseMajorVersion(version: string): number {
if (!version) {
return 0;
Expand Down
9 changes: 4 additions & 5 deletions src/standardLanguageClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict';

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

const extensionName = 'Language Support for Java';
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
Expand Down Expand Up @@ -91,7 +90,7 @@ export class StandardLanguageClient {
if (!port) {
const lsPort = process.env['JDTLS_CLIENT_PORT'];
if (!lsPort) {
serverOptions = prepareExecutable(requirements, workspacePath, getJavaConfig(requirements.java_home), context, false);
serverOptions = prepareExecutable(requirements, workspacePath, context, false);
} else {
serverOptions = () => {
const socket = net.connect(lsPort);
Expand Down Expand Up @@ -217,7 +216,7 @@ export class StandardLanguageClient {
const options: string[] = [];
const info = notification.data as GradleCompatibilityInfo;
const highestJavaVersion = Number(info.highestJavaVersion);
let runtimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
let runtimes = await listJdks(true);
runtimes = runtimes.filter(runtime => {
return runtime.version.major <= highestJavaVersion;
});
Expand Down
2 changes: 1 addition & 1 deletion src/syntaxLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class SyntaxLanguageClient {
didChangeConfiguration: async () => {
await this.languageClient.sendNotification(DidChangeConfigurationNotification.type, {
settings: {
java: getJavaConfig(requirements.java_home),
java: await getJavaConfig(requirements.java_home),
}
});
}
Expand Down
45 changes: 44 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as fs from 'fs';
import * as path from 'path';
import { workspace, WorkspaceConfiguration, commands, Uri, version } from 'vscode';
import { Commands } from './commands';
import { IJavaRuntime } from 'jdk-utils';
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';

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


export function getJavaConfig(javaHome: string) {
export async function getJavaConfig(javaHome: string) {
const origConfig = getJavaConfiguration();
const javaConfig = JSON.parse(JSON.stringify(origConfig));
javaConfig.home = javaHome;
Expand Down Expand Up @@ -215,5 +217,46 @@ export function getJavaConfig(javaHome: string) {
}

javaConfig.telemetry = { enabled: workspace.getConfiguration('redhat.telemetry').get('enabled', false) };
const userConfiguredJREs: any[] = javaConfig.configuration.runtimes;
javaConfig.configuration.runtimes = await addAutoDetectedJdks(userConfiguredJREs);
return javaConfig;
}

async function addAutoDetectedJdks(configuredJREs: any[]): Promise<any[]> {
// search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
const autoDetectedJREs: IJavaRuntime[] = await listJdks();
sortJdksByVersion(autoDetectedJREs);
sortJdksBySource(autoDetectedJREs);
const addedJreNames: Set<string> = new Set<string>();
for (const jre of configuredJREs) {
if (jre.name) {
addedJreNames.add(jre.name);
}
}
for (const jre of autoDetectedJREs) {
const majorVersion: number = jre.version?.major ?? 0;
if (!majorVersion) {
continue;
}

let jreName: string = `JavaSE-${majorVersion}`;
if (majorVersion <= 5) {
jreName = `J2SE-1.${majorVersion}`;
} else if (majorVersion <= 8) {
jreName = `JavaSE-1.${majorVersion}`;
}

if (addedJreNames.has(jreName)) {
continue;
}

configuredJREs.push({
name: jreName,
path: jre.homedir,
});

addedJreNames.add(jreName);
}

return configuredJREs;
}

0 comments on commit 6cc071a

Please sign in to comment.