diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java index 6730e5259..3a85aecaa 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2019 Pivotal, Inc. + * Copyright (c) 2017, 2022 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -30,7 +30,7 @@ import org.springframework.stereotype.Component; @Component public class BootJavaConfig implements InitializingBean { - public static final boolean LIVE_INFORMATION_AUTOMATIC_TRACKING_ENABLED_DEFAULT = true; + public static final boolean LIVE_INFORMATION_AUTOMATIC_TRACKING_ENABLED_DEFAULT = false; public static final int LIVE_INFORMATION_AUTOMATIC_TRACKING_DELAY_DEFAULT = 5000; public static final int LIVE_INFORMATION_FETCH_DATA_RETRY_MAX_NO_DEFAULT = 10; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessCommandHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessCommandHandler.java index 9e12b519f..831fd2b4d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessCommandHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessCommandHandler.java @@ -17,7 +17,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -93,6 +92,8 @@ public class SpringProcessCommandHandler { // try local processes if (SpringProcessConnectorLocal.isAvailable()) { + + // Try cached processes. SpringProcessDescriptor[] processes = localProcessConnector.getProcesses(false, SpringProcessStatus.REGULAR, SpringProcessStatus.AUTO_CONNECT); for (SpringProcessDescriptor process : processes) { if (process.getProcessKey().equals(processKey)) { @@ -100,6 +101,15 @@ public class SpringProcessCommandHandler { return CompletableFuture.completedFuture(null); } } + + processes = localProcessConnector.getProcesses(true, SpringProcessStatus.REGULAR, SpringProcessStatus.AUTO_CONNECT); + for (SpringProcessDescriptor process : processes) { + if (process.getProcessKey().equals(processKey)) { + localProcessConnector.connectProcess(process); + return CompletableFuture.completedFuture(null); + } + } + } // try remote processes diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorService.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorService.java index 3cfb51a83..0f90c1355 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorService.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2022 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -142,7 +142,7 @@ public class SpringProcessConnectorService { * common method to generate process keys from process IDs and process names */ public static String getProcessKey(String processID, String processName) { - return processID + " - " + processName; + return processID; } private void scheduleConnect(ProgressTask progressTask, String processKey, SpringProcessConnector connector, long delay, TimeUnit unit, int retryNo) { diff --git a/vscode-extensions/vscode-spring-boot/lib/debug-config-provider.ts b/vscode-extensions/vscode-spring-boot/lib/debug-config-provider.ts index 4dd4cfff5..247a75484 100644 --- a/vscode-extensions/vscode-spring-boot/lib/debug-config-provider.ts +++ b/vscode-extensions/vscode-spring-boot/lib/debug-config-provider.ts @@ -2,6 +2,7 @@ import { CancellationToken, DebugConfiguration, DebugConfigurationProvider, Prov import * as path from "path"; import * as VSCode from "vscode"; import { Disposable } from "vscode"; +import psList from 'ps-list'; const JMX_VM_ARG = '-Dspring.jmx.enabled=' const ADMIN_VM_ARG = '-Dspring.application.admin.enabled=' @@ -10,7 +11,7 @@ const BOOT_PROJECT_ARG = '-Dspring.boot.project.name='; class SpringBootDebugConfigProvider implements DebugConfigurationProvider { resolveDebugConfigurationWithSubstitutedVariables(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult { - if (isAutoConnect() && this.isActuatorOnClasspath(debugConfiguration)) { + if (isAutoConnect() && isActuatorOnClasspath(debugConfiguration)) { if (debugConfiguration.vmArgs) { if (debugConfiguration.vmArgs.indexOf(JMX_VM_ARG) < 0) { debugConfiguration.vmArgs += ` ${JMX_VM_ARG}true`; @@ -28,28 +29,69 @@ class SpringBootDebugConfigProvider implements DebugConfigurationProvider { return debugConfiguration; } - private isActuatorOnClasspath(debugConfiguration: DebugConfiguration): boolean { - if (Array.isArray(debugConfiguration.classPaths)) { - return !!debugConfiguration.classPaths.find(this.isActuatorJarFile); - } - return false; - } - - private isActuatorJarFile(f: string): boolean { - const fileName = path.basename(f || ""); - if (/^spring-boot-actuator-\d+\.\d+\.\d+(.*)?.jar$/.test(fileName)) { - return true; - } - return false; - } +} +interface ProcessEvent { + type: string; + pid: number; + shellProcessId: number } export function startDebugSupport(): Disposable { - // VSCode.debug.onDidStartDebugSession(handleDebugSessionStarted); + VSCode.debug.onDidReceiveDebugSessionCustomEvent(handleCustomDebugEvent); return VSCode.debug.registerDebugConfigurationProvider('java', new SpringBootDebugConfigProvider(), VSCode.DebugConfigurationProviderTriggerKind.Initial); } -function isAutoConnect(): boolean { - return VSCode.workspace.getConfiguration("boot-java.live-information.automatic-tracking")?.get('on'); +async function handleCustomDebugEvent(e: VSCode.DebugSessionCustomEvent): Promise { + if (e.session?.type === 'java' && e?.body?.type === 'processid') { + const debugConfiguration: DebugConfiguration = e.session.configuration; + if (isBootAppWithJmxSetup(debugConfiguration)) { + setTimeout(async () => { + const pid = await getAppPid(e.body as ProcessEvent); + const processKey = pid.toString(); + VSCode.commands.executeCommand('sts/livedata/connect', { processKey }); + }, 500); + } + } +} + +async function getAppPid(e: ProcessEvent): Promise { + if (e.pid) { + return e.pid; + } else if (e.shellProcessId) { + const processes = await psList(); + const appProcess = processes.find(p => p.ppid === e.shellProcessId); + if (appProcess) { + return appProcess.pid; + } + throw Error(`No child process found for parent shell process with pid = ${e.shellProcessId}`); + } else { + throw Error('No pid or parent shell process id available'); + } +} + +function isActuatorOnClasspath(debugConfiguration: DebugConfiguration): boolean { + if (Array.isArray(debugConfiguration.classPaths)) { + return !!debugConfiguration.classPaths.find(isActuatorJarFile); + } + return false; +} + +function isActuatorJarFile(f: string): boolean { + const fileName = path.basename(f || ""); + if (/^spring-boot-actuator-\d+\.\d+\.\d+(.*)?.jar$/.test(fileName)) { + return true; + } + return false; +} + +function isBootAppWithJmxSetup(debugConfiguration: DebugConfiguration): boolean { + return debugConfiguration.vmArgs.indexOf(`${JMX_VM_ARG}true`) >= 0 + && debugConfiguration.vmArgs.indexOf(`${ADMIN_VM_ARG}true`) >= 0 + && debugConfiguration.vmArgs.indexOf(`${BOOT_PROJECT_ARG}${debugConfiguration.projectName}`) >= 0 + && isActuatorOnClasspath(debugConfiguration); +} + +function isAutoConnect(): boolean { + return VSCode.workspace.getConfiguration("boot-java.live-information.automatic-connection")?.get('on'); } diff --git a/vscode-extensions/vscode-spring-boot/lib/live-hover-connect-ui.ts b/vscode-extensions/vscode-spring-boot/lib/live-hover-connect-ui.ts index 432a2001e..854f44b6a 100644 --- a/vscode-extensions/vscode-spring-boot/lib/live-hover-connect-ui.ts +++ b/vscode-extensions/vscode-spring-boot/lib/live-hover-connect-ui.ts @@ -7,7 +7,8 @@ import { ActivatorOptions } from '@pivotal-tools/commons-vscode'; interface ProcessCommandInfo { processKey : string; label: string; - action: string + action: string; + projectName: string; } async function liveHoverConnectHandler() { diff --git a/vscode-extensions/vscode-spring-boot/package.json b/vscode-extensions/vscode-spring-boot/package.json index e3eaee78e..a4f12974a 100644 --- a/vscode-extensions/vscode-spring-boot/package.json +++ b/vscode-extensions/vscode-spring-boot/package.json @@ -75,15 +75,10 @@ "type": "object", "title": "Boot-Java Configuration", "properties": { - "boot-java.live-information.automatic-tracking.on": { + "boot-java.live-information.automatic-connection.on": { "type": "boolean", "default": true, - "description": "Live Information - Automatic Process Tracking Enabled" - }, - "boot-java.live-information.automatic-tracking.delay": { - "type": "number", - "default": 5000, - "description": "Live Information - Automatic Process Tracking Delay in ms" + "description": "Live Information - Automatic Process Connection Enabled" }, "boot-java.live-information.fetch-data.max-retries": { "type": "number", @@ -518,13 +513,14 @@ }, "dependencies": { "@pivotal-tools/commons-vscode": "file:../commons-vscode/pivotal-tools-commons-vscode-0.2.4.tgz", + "ps-list": "^7.2.0", "vscode-languageclient": "^7.0.0" }, "devDependencies": { "@types/node": "^16.11.11", "@types/vscode": "^1.53.0", "typescript": "^4.1.2", - "vsce": "^2.5.1" + "vsce": "^2.6.7" }, "extensionDependencies": [ "redhat.java" diff --git a/vscode-extensions/vscode-spring-boot/tsconfig.json b/vscode-extensions/vscode-spring-boot/tsconfig.json index 1905ffea7..1905844a5 100644 --- a/vscode-extensions/vscode-spring-boot/tsconfig.json +++ b/vscode-extensions/vscode-spring-boot/tsconfig.json @@ -9,7 +9,8 @@ "declaration": true, "outDir": "out", "sourceMap": true, - "rootDir": "." + "rootDir": ".", + "esModuleInterop": true }, "include": [ "typings/*.d.ts",