From b4292f63c9c198c6d0f10857df80aad358cd1fb7 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Sun, 17 Nov 2024 18:53:29 +0100 Subject: [PATCH] GH-1410: adopt new jmx method from boot 3 apps to fetch the condition report and deal correctly with conditions embedded in app node --- .../livehover/v2/LiveConditionalParser.java | 21 ++++++++----- ...SpringProcessLiveDataExtractorOverJMX.java | 31 ++++++++++++++----- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/LiveConditionalParser.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/LiveConditionalParser.java index 7063a59c6..d9a440f8e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/LiveConditionalParser.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/LiveConditionalParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2024 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 @@ -11,6 +11,7 @@ package org.springframework.ide.vscode.boot.java.livehover.v2; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Optional; @@ -50,12 +51,19 @@ public class LiveConditionalParser { if (StringUtil.hasText(autoConfigRecord)) { JSONObject autoConfigReport = new JSONObject(autoConfigRecord); if (autoConfigReport.has("contexts")) { - //more recently the report is nested inside the 'application' context. - autoConfigReport = autoConfigReport.getJSONObject("contexts").getJSONObject("application"); + //more recently the report is nested inside an 'application' context, but the name of the node depends on the app + + JSONObject contexts = autoConfigReport.getJSONObject("contexts"); + Iterator keys = contexts.keys(); + if (keys.hasNext()) { + autoConfigReport = contexts.getJSONObject(keys.next()); + } } + for (LiveConditional c : getConditionalsFromPositiveMatches(autoConfigReport)) { allConditionals.add(c); } + for (LiveConditional c : getConditionalsFromNegativeMatches(autoConfigReport)) { allConditionals.add(c); } @@ -135,8 +143,7 @@ public class LiveConditionalParser { return conditions; } - private void parseConditionalsFromContentList(List conditionals, String typeInfo, - JSONArray contentList) { + private void parseConditionalsFromContentList(List conditionals, String typeInfo, JSONArray contentList) { for (Object content : contentList) { if (content instanceof JSONObject) { JSONObject conditionalJson = (JSONObject) content; @@ -154,9 +161,7 @@ public class LiveConditionalParser { } } - - public static LiveConditional[] parse(String autoConfigRecord, String appProcessId, - String appProcessName) { + public static LiveConditional[] parse(String autoConfigRecord, String appProcessId, String appProcessName) { return new LiveConditionalParser(autoConfigRecord, appProcessId, appProcessName).parse(); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessLiveDataExtractorOverJMX.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessLiveDataExtractorOverJMX.java index d00ded11e..531b64a5f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessLiveDataExtractorOverJMX.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessLiveDataExtractorOverJMX.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2024 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 @@ -29,6 +29,7 @@ import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.Query; import javax.management.QueryExp; +import javax.management.ReflectionException; import javax.management.remote.JMXConnector; import org.json.JSONArray; @@ -604,8 +605,15 @@ public class SpringProcessLiveDataExtractorOverJMX { public LiveConditional[] getConditionals(MBeanServerConnection connection, String domain, String processId, String processName) { try { + //Boot 3.x + Object result = getActuatorDataFromOperation(connection, getObjectName(domain, "type=Endpoint,name=Conditions"), "conditions"); + if (result != null) { + String report = gson.toJson(result); + return LiveConditionalParser.parse(report, processId, processName); + } + //Boot 2.x - Object result = getActuatorDataFromOperation(connection, getObjectName(domain, "type=Endpoint,name=Conditions"), "applicationConditionEvaluation"); + result = getActuatorDataFromOperation(connection, getObjectName(domain, "type=Endpoint,name=Conditions"), "applicationConditionEvaluation"); if (result != null) { String report = gson.toJson(result); return LiveConditionalParser.parse(report, processId, processName); @@ -621,7 +629,7 @@ public class SpringProcessLiveDataExtractorOverJMX { } catch (IOException e) { //ignore. Happens a lot when apps are stopped while we try to talk to them. } catch (Exception e) { - // TODO Auto-generated catch block + // ignore, might happen when communication with the running app is difficult } return null; @@ -655,7 +663,6 @@ public class SpringProcessLiveDataExtractorOverJMX { } public LiveProperties getProperties(MBeanServerConnection connection, String environment) throws Exception { - try { if (environment != null) { return LivePropertiesJsonParser.parseProperties(environment); @@ -666,21 +673,20 @@ public class SpringProcessLiveDataExtractorOverJMX { return null; } - - public String getEnvironment(MBeanServerConnection connection, String domain) throws Exception { try { - Object result = getActuatorDataFromAttribute(connection, getObjectName(domain, "type=Endpoint,name=environmentEndpoint"), "Data"); + Object result = getActuatorDataFromOperation(connection, getObjectName(domain, "type=Endpoint,name=Env"), "environment"); if (result != null) { String environment = gson.toJson(result); return environment; } - result = getActuatorDataFromOperation(connection, getObjectName(domain, "type=Endpoint,name=Env"), "environment"); + result = getActuatorDataFromAttribute(connection, getObjectName(domain, "type=Endpoint,name=environmentEndpoint"), "Data"); if (result != null) { String environment = gson.toJson(result); return environment; } + } catch (IOException e) { //ignore... probably just because app is stopped } catch (ExecutionException e) { @@ -700,6 +706,9 @@ public class SpringProcessLiveDataExtractorOverJMX { catch (InstanceNotFoundException|IOException e) { return null; } + catch (ReflectionException e) { + return null; + } } return null; } @@ -712,6 +721,9 @@ public class SpringProcessLiveDataExtractorOverJMX { catch (InstanceNotFoundException|IOException e) { return null; } + catch (ReflectionException e) { + return null; + } } return null; } @@ -724,6 +736,9 @@ public class SpringProcessLiveDataExtractorOverJMX { catch (InstanceNotFoundException|IOException e) { return null; } + catch (ReflectionException e) { + return null; + } } return null; }