From cd276ddbc499a8156d36417aeb0d27dfc17cf57e Mon Sep 17 00:00:00 2001 From: "nsingh@pivotal.io" Date: Mon, 11 Feb 2019 13:35:20 -0800 Subject: [PATCH] PT 163178235 - Add live properties parsing for Boot 2.x Live properties parsing for Boot 2.x was missing and was not appearing when hovering over @Value properties --- .../boot/app/cli/AbstractSpringBootApp.java | 16 +++ .../commons/boot/app/cli/SpringBootApp.java | 3 + .../cli/liveproperties/LiveEnvJsonParser.java | 56 +++++++++++ .../liveproperties/LiveEnvJsonParser1x.java | 82 ++++++++++++++++ .../liveproperties/LiveEnvJsonParser2x.java | 97 +++++++++++++++++++ .../cli/liveproperties/LiveProperties.java | 38 ++++++++ .../app/cli/liveproperties/LiveProperty.java | 59 +++++++++++ .../liveproperties/LivePropertySource.java | 41 ++++++++ .../boot/java/value/ValueHoverProvider.java | 45 ++++----- 9 files changed, 410 insertions(+), 27 deletions(-) create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser.java create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser1x.java create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser2x.java create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperties.java create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperty.java create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LivePropertySource.java diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/AbstractSpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/AbstractSpringBootApp.java index 294edb99f..350ae5fd5 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/AbstractSpringBootApp.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/AbstractSpringBootApp.java @@ -43,6 +43,8 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel; +import org.springframework.ide.vscode.commons.boot.app.cli.liveproperties.LiveEnvJsonParser; +import org.springframework.ide.vscode.commons.boot.app.cli.liveproperties.LiveProperties; import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.Boot1xRequestMapping; import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping; import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMappingsParser20; @@ -623,6 +625,20 @@ public abstract class AbstractSpringBootApp implements SpringBootApp { }); } + @Override + public LiveProperties getLiveProperties() throws Exception { + + try { + String envJson = getEnvironment(); + if (envJson != null) { + return LiveEnvJsonParser.parseProperties(envJson); + } + } catch (Exception e) { + logger.error("error resolving live properties from environment endpoint", e); + } + return null; + } + protected String getPortViaAdmin(MBeanServerConnection connection) throws Exception { try { String DEFAULT_OBJECT_NAME = "org.springframework.boot:type=Admin,name=SpringApplication"; diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java index 533ff3d67..fec616f76 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java @@ -16,6 +16,7 @@ import java.util.Optional; import java.util.Properties; import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel; +import org.springframework.ide.vscode.commons.boot.app.cli.liveproperties.LiveProperties; import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping; import reactor.core.Disposable; @@ -41,6 +42,8 @@ public interface SpringBootApp extends Disposable { Optional> getLiveConditionals() throws Exception; Properties getSystemProperties() throws Exception; + LiveProperties getLiveProperties() throws Exception; + default String getSystemProperty(String string) throws Exception { Object r = getSystemProperties().get(string); if (r instanceof String) { diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser.java new file mode 100644 index 000000000..082da3a5a --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli.liveproperties; + +import java.util.List; + +import org.json.JSONException; +import org.json.JSONObject; + +public abstract class LiveEnvJsonParser { + + /** + * Parse live properties from the given JSON input. Returns null if no live + * properties could be parsed + * + * @param jsonInput + * @return live properties if parsed, or null otherwise + * @throws Exception + */ + public LiveProperties parse(String jsonInput) throws Exception { + + JSONObject envObj = toJson(jsonInput); + + List propertySources = readProperties(envObj); + if (propertySources != null && !propertySources.isEmpty()) { + return new LiveProperties(propertySources); + } else { + return null; + } + } + + protected JSONObject toJson(String json) throws JSONException { + return new JSONObject(json); + } + + protected abstract List readProperties(JSONObject envObj) throws Exception; + + public static LiveProperties parseProperties(String jsonInput) throws Exception { + LiveEnvJsonParser2x boot2x = new LiveEnvJsonParser2x(); + LiveProperties properties = boot2x.parse(jsonInput); + if (properties == null) { + LiveEnvJsonParser1x boot1x = new LiveEnvJsonParser1x(); + properties = boot1x.parse(jsonInput); + } + return properties; + } + +} diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser1x.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser1x.java new file mode 100644 index 000000000..a3b16976f --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser1x.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli.liveproperties; + +import java.util.Iterator; +import java.util.List; + +import org.json.JSONObject; + +import com.google.common.collect.ImmutableList; + +public class LiveEnvJsonParser1x extends LiveEnvJsonParser { + + public LiveEnvJsonParser1x() { + + } + + /** + * + * @param envObj + * @return non-null PropertySources. Content in the PropertySources may be empty + * if no sources are found + * @throws Exception + */ + @Override + protected List readProperties(JSONObject allSourcesJson) throws Exception { + ImmutableList.Builder allSources = ImmutableList.builder(); + + if (allSourcesJson != null) { + Iterator keys = allSourcesJson.keys(); + if (keys != null) { + while (keys.hasNext()) { + Object key = keys.next(); + if (key instanceof String) { + String sourceName = (String) key; + // Skip profiles + if (!"profiles".equals(sourceName)) { + Object sourceObj = allSourcesJson.opt(sourceName); + ImmutableList.Builder parsedProps = ImmutableList.builder(); + + if (sourceObj instanceof JSONObject) { + JSONObject source = (JSONObject) sourceObj; + Iterator propKeys = source.keys(); + if (propKeys != null) { + while (propKeys.hasNext()) { + Object propObjKey = propKeys.next(); + if (propObjKey instanceof String) { + String propName = (String) propObjKey; + Object valObj = source.optString(propName); + if (valObj instanceof String) { + String value = (String) valObj; + LiveProperty property = LiveProperty + .builder() // + .source(sourceName) // + .property(propName) // + .value(value) // + .build(); + parsedProps.add(property); + } + } + } + } + } + LivePropertySource propertySource = new LivePropertySource(sourceName, parsedProps.build()); + allSources.add(propertySource); + } + } + } + } + } + + return allSources.build(); + } +} diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser2x.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser2x.java new file mode 100644 index 000000000..d396d36af --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveEnvJsonParser2x.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli.liveproperties; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +import com.google.common.collect.ImmutableList; + +public class LiveEnvJsonParser2x extends LiveEnvJsonParser { + + public LiveEnvJsonParser2x() { + + } + + /** + * + * @param envObj + * @return non-null PropertySources. Content in the PropertySources may be empty + * if no sources are found + * @throws Exception + */ + @Override + protected List readProperties(JSONObject envObj) throws Exception { + ImmutableList.Builder allSources = ImmutableList.builder(); + + Object sourcesObj = envObj.opt("propertySources"); + + if (sourcesObj instanceof JSONArray) { + JSONArray props = (JSONArray) sourcesObj; + for (int i = 0; i < props.length(); i++) { + Object object = props.opt(i); + if (object instanceof JSONObject) { + JSONObject propObj = (JSONObject) object; + String sourceName = propObj.optString("name"); + if (sourceName != null) { + Object opt2 = propObj.opt("properties"); + List properties = parseProperties(sourceName, opt2); + + LivePropertySource propertySource = new LivePropertySource(sourceName, properties); + + allSources.add(propertySource); + } + } + } + } + return allSources.build(); + } + + private List parseProperties(String sourceName, Object opt2) { + List properties = new ArrayList<>(); + + if (opt2 instanceof JSONObject) { + JSONObject jsonObj = (JSONObject) opt2; + Iterator keys = jsonObj.keys(); + if (keys != null) { + while (keys.hasNext()) { + Object key = keys.next(); + if (key instanceof String) { + String propKey = (String) key; + Object propContentObj = jsonObj.opt(propKey); + if (propContentObj != null) { + String value = getValue(propContentObj); + LiveProperty property = LiveProperty.builder() // + .source(sourceName) // + .property(propKey) // + .value(value) // + .build(); + properties.add(property); + } + } + } + } + } + return properties; + } + + private String getValue(Object propContentObj) { + if (propContentObj instanceof JSONObject) { + JSONObject jsonObj = (JSONObject) propContentObj; + return jsonObj.optString("value"); + } + return null; + } +} diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperties.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperties.java new file mode 100644 index 000000000..0319171a6 --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperties.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli.liveproperties; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class LiveProperties { + + private final List sources; + + public LiveProperties(List sources) { + this.sources = sources != null ? ImmutableList.copyOf(sources) : ImmutableList.of(); + } + + + public List getProperties(String propertyName) { + List foundProperties = new ArrayList<>(); + for (LivePropertySource source : sources) { + LiveProperty property = source.getProperty(propertyName); + if (property != null) { + foundProperties.add(property); + } + } + return foundProperties; + } + +} diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperty.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperty.java new file mode 100644 index 000000000..0c28d642c --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LiveProperty.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli.liveproperties; + +public class LiveProperty { + + private String source; + private String property; + private String value; + + public String getSource() { + return source; + } + + public String getProperty() { + return property; + } + + public String getValue() { + return value; + } + + public static class LivePropertyBuilder { + + private LiveProperty liveProperty = new LiveProperty(); + + public LivePropertyBuilder source(String source) { + liveProperty.source = source; + return this; + } + + public LivePropertyBuilder property(String property) { + liveProperty.property = property; + return this; + } + + public LivePropertyBuilder value(String value) { + liveProperty.value = value; + return this; + } + + public LiveProperty build() { + return liveProperty; + } + } + + public static LivePropertyBuilder builder() { + return new LivePropertyBuilder(); + } + +} diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LivePropertySource.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LivePropertySource.java new file mode 100644 index 000000000..07330fd0f --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/liveproperties/LivePropertySource.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli.liveproperties; + +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class LivePropertySource { + + private final List properties; + private final String sourceName; + + + public LivePropertySource(String sourceName, List properties) { + this.sourceName = sourceName; + this.properties = properties != null ? ImmutableList.copyOf(properties) : ImmutableList.of(); + } + + public String getSourceName() { + return this.sourceName; + } + + public LiveProperty getProperty(String propertyName) { + for (LiveProperty liveProperty : properties) { + if (liveProperty.getProperty().equals(propertyName)) { + return liveProperty; + } + } + return null; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java index 9a29cebfe..dde17bfc8 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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,7 +11,7 @@ package org.springframework.ide.vscode.boot.java.value; import java.util.HashMap; -import java.util.Iterator; +import java.util.List; import java.util.Map; import org.eclipse.jdt.core.dom.ASTNode; @@ -24,10 +24,11 @@ import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.json.JSONObject; import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.boot.app.cli.liveproperties.LiveProperties; +import org.springframework.ide.vscode.commons.boot.app.cli.liveproperties.LiveProperty; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -74,26 +75,19 @@ public class ValueHoverProvider implements HoverProvider { String propertyKey = value.substring(range.getStart(), range.getEnd()); if (propertyKey != null) { - Map allProperties = getPropertiesFromProcesses(runningApps); + Map allProperties = getPropertiesFromProcesses(runningApps); StringBuilder hover = new StringBuilder(); for (SpringBootApp app : allProperties.keySet()) { - JSONObject properties = allProperties.get(app); - Iterator keys = properties.keys(); - while (keys.hasNext()) { - String key = (String) keys.next(); - if (properties.get(key) instanceof JSONObject) { - JSONObject props = properties.getJSONObject(key); - - if (props.has(propertyKey)) { - String propertyValue = props.getString(propertyKey); - - hover.append(propertyKey + " : " + propertyValue); - hover.append(" (from: " + key + ")\n\n"); - hover.append(LiveHoverUtils.niceAppName(app)); - hover.append("\n\n"); - } + LiveProperties properties = allProperties.get(app); + List foundProperties = properties.getProperties(propertyKey); + if (foundProperties != null) { + for (LiveProperty liveProp : foundProperties) { + hover.append(propertyKey + " : " + liveProp.getValue()); + hover.append(" (from: " + liveProp.getSource() + ")\n\n"); + hover.append(LiveHoverUtils.niceAppName(app)); + hover.append("\n\n"); } } } @@ -115,17 +109,14 @@ public class ValueHoverProvider implements HoverProvider { return null; } - public Map getPropertiesFromProcesses(SpringBootApp[] runningApps) { - Map result = new HashMap<>(); + public Map getPropertiesFromProcesses(SpringBootApp[] runningApps) { + Map result = new HashMap<>(); try { for (SpringBootApp app : runningApps) { - String environment = app.getEnvironment(); - if (environment != null) { - JSONObject env = new JSONObject(environment); - if (env != null) { - result.put(app, env); - } + LiveProperties liveProperties = app.getLiveProperties(); + if (liveProperties != null) { + result.put(app, liveProperties); } } }