diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java index 4f19b409b..b018b482b 100644 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.CompletionException; import org.eclipse.core.internal.resources.Project; import org.eclipse.core.internal.resources.ProjectDescription; @@ -31,6 +32,8 @@ import org.eclipse.jdt.ls.core.internal.managers.BasicFileDetector; import org.eclipse.jdt.ls.core.internal.managers.DigestStore; import org.eclipse.jdt.ls.core.internal.preferences.Preferences; +import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; + import com.microsoft.java.builder.JavaProblemChecker; import com.microsoft.gradle.bs.importer.model.BuildServerPreferences; import com.microsoft.gradle.bs.importer.model.Telemetry; @@ -54,6 +57,7 @@ public class GradleBuildServerProjectImporter extends AbstractProjectImporter { public static final String SETTINGS_GRADLE_DESCRIPTOR = "settings.gradle"; public static final String SETTINGS_GRADLE_KTS_DESCRIPTOR = "settings.gradle.kts"; public static final String ANDROID_MANIFEST = "AndroidManifest.xml"; + private boolean isResolved = true; @Override public boolean applies(IProgressMonitor monitor) throws OperationCanceledException, CoreException { @@ -172,9 +176,20 @@ public void importToWorkspace(IProgressMonitor monitor) throws OperationCanceled ); BuildServerPreferences data = getBuildServerPreferences(); params.setData(data); - InitializeBuildResult initializeResult = buildServer.buildInitialize(params).join(); - buildServer.onBuildInitialized(); - // TODO: save the capabilities of this server + try { + InitializeBuildResult initializeResult = buildServer.buildInitialize(params).join(); + buildServer.onBuildInitialized(); + // TODO: save the capabilities of this server + } catch (CompletionException e) { + Throwable cause = e.getCause(); + if (e.getCause() instanceof ResponseErrorException responseError) { + if ("Unhandled method build/initialize".equals(responseError.getMessage())) { + JavaLanguageServerPlugin.logException("Failed to start Gradle Build Server, use BuildShip instead", null); + this.isResolved = false; + return; + } + } + } if (monitor.isCanceled()) { return; @@ -207,6 +222,9 @@ public boolean isResolved(File folder) throws OperationCanceledException, CoreEx // TOOD: Once the upstream GradleProjectImporter has been updated to not import when // the gradle project has already imported by other importers, we can modify this logic // so that Maven importer can be involved for other projects. + if (!this.isResolved){ + return false; + } for (IProject project : ProjectUtils.getAllProjects()) { if (Utils.isGradleBuildServerProject(project) && project.getLocation().toPath().startsWith(folder.toPath())) { diff --git a/extension/src/Extension.ts b/extension/src/Extension.ts index 35ce42f95..1a90b71e5 100644 --- a/extension/src/Extension.ts +++ b/extension/src/Extension.ts @@ -260,7 +260,6 @@ export class Extension { }); } const activated = !!(await this.rootProjectsStore.getProjectRoots()).length; - this.bspProxy.prepareToStart(); if (!this.server.isReady()) { await this.server.start(); } diff --git a/extension/src/bs/BspProxy.ts b/extension/src/bs/BspProxy.ts index cdf90b3e1..1c518814d 100644 --- a/extension/src/bs/BspProxy.ts +++ b/extension/src/bs/BspProxy.ts @@ -16,6 +16,7 @@ import { sendInfo } from "vscode-extension-telemetry-wrapper"; export class BspProxy { private buildServerConnector: BuildServerConnector; private jdtlsImporterConnector: JdtlsImporterConnector; + private buildServerStart: boolean; constructor(context: vscode.ExtensionContext, private readonly logger: Logger) { this.buildServerConnector = new BuildServerConnector(); @@ -24,8 +25,8 @@ export class BspProxy { /** * This function needs to be called before we start Java Gradle Server. */ - public prepareToStart(): void { - this.buildServerConnector.setupBuildServerPipeStream(); + public prepareToStart(): boolean { + return this.buildServerConnector.setupBuildServerPipeStream(); } /** @@ -37,11 +38,12 @@ export class BspProxy { public async start(): Promise { await this.jdtlsImporterConnector.waitForImporterPipePath(); await this.jdtlsImporterConnector.setupImporterPipeStream(); - - this.setupMessageForwarding( - this.jdtlsImporterConnector.getImporterConnection(), - this.buildServerConnector.getServerConnection() - ); + if (this.buildServerStart) { + this.setupMessageForwarding( + this.jdtlsImporterConnector.getImporterConnection(), + this.buildServerConnector.getServerConnection() + ); + } this.jdtlsImporterConnector.startListening(); } @@ -53,20 +55,23 @@ export class BspProxy { importerConnection: rpc.MessageConnection | null, buildServerConnection: rpc.MessageConnection | null ): void { - importerConnection?.onRequest((method, params) => { + if (!importerConnection || !buildServerConnection) { + return; + } + importerConnection.onRequest((method, params) => { if (params !== null) { - return buildServerConnection?.sendRequest(method, params); + return buildServerConnection.sendRequest(method, params); } - return buildServerConnection?.sendRequest(method); + return buildServerConnection.sendRequest(method); }); - buildServerConnection?.onNotification((method, params) => { + buildServerConnection.onNotification((method, params) => { if (params !== null) { - return importerConnection?.sendNotification(method, params); + return importerConnection.sendNotification(method, params); } - importerConnection?.sendNotification(method); + importerConnection.sendNotification(method); }); - importerConnection?.onError(([error]) => { + importerConnection.onError(([error]) => { this.logger.error(`Error on importerConnection: ${error.message}`); sendInfo("", { kind: "bspProxy-importerConnectionError", @@ -76,7 +81,7 @@ export class BspProxy { // TODO: Implement more specific error handling logic here }); - buildServerConnection?.onError(([error]) => { + buildServerConnection.onError(([error]) => { this.logger.error(`Error on buildServerConnection: ${error.message}`); sendInfo("", { kind: "bspProxy-buildServerConnectionError", @@ -86,6 +91,9 @@ export class BspProxy { // TODO: Implement more specific error handling logic here }); } + public setBuildServerStarted(started: boolean): void { + this.buildServerStart = started; + } public closeConnection(): void { this.buildServerConnector.close(); diff --git a/extension/src/bs/BuildServerConnector.ts b/extension/src/bs/BuildServerConnector.ts index 0ff1953c5..f7d61f73d 100644 --- a/extension/src/bs/BuildServerConnector.ts +++ b/extension/src/bs/BuildServerConnector.ts @@ -15,8 +15,11 @@ export class BuildServerConnector { * Generates a random pipe name, creates a pipe server and * waiting for the connection from the Java build server. */ - public setupBuildServerPipeStream(): void { + public setupBuildServerPipeStream(): boolean { this.serverPipePath = getRandomPipeName(); + if (this.serverPipePath === "") { + return false; + } this.serverPipeServer = net.createServer((socket: net.Socket) => { this.serverConnection = rpc.createMessageConnection( new rpc.StreamMessageReader(socket), @@ -25,6 +28,7 @@ export class BuildServerConnector { this.serverConnection.listen(); }); this.serverPipeServer.listen(this.serverPipePath); + return true; } public getServerConnection(): rpc.MessageConnection | null { diff --git a/extension/src/server/GradleServer.ts b/extension/src/server/GradleServer.ts index 4d214ae88..3bc2675ae 100644 --- a/extension/src/server/GradleServer.ts +++ b/extension/src/server/GradleServer.ts @@ -49,6 +49,17 @@ export class GradleServer { return this.languageServerPipePath; } public async start(): Promise { + let startBuildServer = false; + if (redHatJavaInstalled()) { + const isPrepared = this.bspProxy.prepareToStart(); + if (isPrepared) { + startBuildServer = true; + } else { + this.logger.error("Failed to generate build server pipe path, build server will not start"); + } + } + this.bspProxy.setBuildServerStarted(startBuildServer); + this.taskServerPort = await getPort(); const cwd = this.context.asAbsolutePath("lib"); const cmd = path.join(cwd, getGradleServerCommand()); @@ -61,13 +72,12 @@ export class GradleServer { await vscode.window.showErrorMessage(NO_JAVA_EXECUTABLE); return; } - const startBuildServer = redHatJavaInstalled() ? "true" : "false"; const args = [ quoteArg(`--port=${this.taskServerPort}`), quoteArg(`--startBuildServer=${startBuildServer}`), quoteArg(`--languageServerPipePath=${this.languageServerPipePath}`), ]; - if (startBuildServer === "true") { + if (startBuildServer) { const buildServerPipeName = this.bspProxy.getBuildServerPipeName(); args.push(quoteArg(`--pipeName=${buildServerPipeName}`)); args.push(quoteArg(`--bundleDir=${bundleDirectory}`));