This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new b1962d6e46f CAMEL-21241: properties component - Should capture details
about resolved placeholders (#15625)
b1962d6e46f is described below
commit b1962d6e46f5e3f59db312d443c0050716a6b90b
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Sep 19 16:23:43 2024 +0200
CAMEL-21241: properties component - Should capture details about resolved
placeholders (#15625)
---
.../org/apache/camel/spi/PropertiesComponent.java | 8 ++
.../apache/camel/spi/PropertiesResolvedValue.java | 24 ++++++
.../properties/DefaultPropertiesLookup.java | 9 ++-
.../DefaultPropertiesLookupListener.java | 62 +++++++++++++++
.../properties/DefaultPropertiesParser.java | 35 +++++---
.../component/properties/PropertiesComponent.java | 22 +++--
.../camel/impl/console/PropertiesDevConsole.java | 20 ++++-
.../PropertiesComponentResolvedValueTest.java | 93 ++++++++++++++++++++++
.../camel/main/MainConfigurationDevConsole.java | 18 +++++
.../core/commands/process/ListProperties.java | 26 +++++-
10 files changed, 299 insertions(+), 18 deletions(-)
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
index ef725a8ec01..e078809d11e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java
@@ -84,6 +84,14 @@ public interface PropertiesComponent extends StaticService {
*/
Optional<String> resolveProperty(String key);
+ /**
+ * Returns metadata about a property which has successfully been resolved.
+ *
+ * @param key the name of the property
+ * @return the property value and metadata if present
+ */
+ Optional<PropertiesResolvedValue> getResolvedValue(String key);
+
/**
* Loads the properties from the default locations and sources.
*
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesResolvedValue.java
b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesResolvedValue.java
new file mode 100644
index 00000000000..2863b5065f7
--- /dev/null
+++
b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesResolvedValue.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spi;
+
+/**
+ * Data about a {@link PropertiesComponent} property placeholder that has been
resolved to a value by Camel.
+ */
+public record PropertiesResolvedValue(String name, String originalValue,
String value, String defaultValue, String source) {
+
+}
diff --git
a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookup.java
b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookup.java
index 3f8ad715e0a..695edcee640 100644
---
a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookup.java
+++
b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookup.java
@@ -24,6 +24,8 @@ import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.LoadablePropertiesSource;
import org.apache.camel.spi.PropertiesSource;
import org.apache.camel.util.OrderedLocationProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Default {@link PropertiesLookup} which lookup properties from a {@link
java.util.Properties} with all existing
@@ -31,6 +33,8 @@ import org.apache.camel.util.OrderedLocationProperties;
*/
public class DefaultPropertiesLookup implements PropertiesLookup {
+ private static final Logger LOG =
LoggerFactory.getLogger(DefaultPropertiesLookup.class);
+
private final PropertiesComponent component;
public DefaultPropertiesLookup(PropertiesComponent component) {
@@ -40,7 +44,9 @@ public class DefaultPropertiesLookup implements
PropertiesLookup {
@Override
public String lookup(String name, String defaultValue) {
try {
- return doLookup(name, defaultValue);
+ String answer = doLookup(name, defaultValue);
+ LOG.trace("lookup(name: {} default: {}) -> {}", name,
defaultValue, answer);
+ return answer;
} catch (NoTypeConversionAvailableException e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
@@ -119,6 +125,7 @@ public class DefaultPropertiesLookup implements
PropertiesLookup {
}
private void onLookup(String name, String value, String defaultValue,
String source) {
+ LOG.trace("Property (name: {} default: {}) resolved from source: {} ->
{}", name, defaultValue, source, value);
for (PropertiesLookupListener listener :
component.getPropertiesLookupListeners()) {
try {
listener.onLookup(name, value, defaultValue, source);
diff --git
a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookupListener.java
b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookupListener.java
new file mode 100644
index 00000000000..d9af8fad85f
--- /dev/null
+++
b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesLookupListener.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.properties;
+
+import java.util.Map;
+
+import org.apache.camel.PropertiesLookupListener;
+import org.apache.camel.spi.PropertiesResolvedValue;
+import org.apache.camel.support.LRUCacheFactory;
+import org.apache.camel.support.service.ServiceSupport;
+
+/**
+ * A {@link PropertiesLookupListener} listener that captures the resolved
properties for dev consoles, management and
+ * troubleshooting purposes.
+ */
+public class DefaultPropertiesLookupListener extends ServiceSupport implements
PropertiesLookupListener {
+
+ private Map<String, PropertiesResolvedValue> properties;
+
+ @Override
+ public void onLookup(String name, String value, String defaultValue,
String source) {
+ properties.put(name, new PropertiesResolvedValue(name, value, value,
defaultValue, source));
+ }
+
+ void updateValue(String name, String newValue, String newSource) {
+ var p = properties.get(name);
+ if (p != null) {
+ String source = newSource != null ? newSource : p.source();
+ properties.put(name, new PropertiesResolvedValue(p.name(),
p.originalValue(), newValue, p.defaultValue(), source));
+ }
+ }
+
+ public PropertiesResolvedValue getProperty(String key) {
+ return properties.get(key);
+ }
+
+ @Override
+ protected void doBuild() throws Exception {
+ // use a cache with max limit to avoid capturing endless property
values
+ // if there are a lot of dynamic values
+ properties = LRUCacheFactory.newLRUCache(1000);
+ }
+
+ @Override
+ protected void doShutdown() throws Exception {
+ properties.clear();
+ }
+}
diff --git
a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java
b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java
index efcdac9b64e..43edd497bb1 100644
---
a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java
+++
b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java
@@ -118,7 +118,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
input = input.replace("?nested=false", "");
}
if (nested) {
- return doParseNested(input, new HashSet<>());
+ return doParseNested(null, input, new HashSet<>());
} else {
return doParse(input);
}
@@ -137,7 +137,8 @@ public class DefaultPropertiesParser implements
PropertiesParser {
StringBuilder answer = new StringBuilder(input.length());
Property property;
- while ((property = readProperty(input)) != null) {
+ String prevKey = null;
+ while ((property = readProperty(prevKey, input)) != null) {
String before = input.substring(0, property.getBeginIndex());
String after = input.substring(property.getEndIndex());
String parsed = property.getValue();
@@ -149,6 +150,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
return null;
}
input = after;
+ prevKey = property.getKey();
}
if (!input.isEmpty()) {
answer.append(input);
@@ -163,13 +165,13 @@ public class DefaultPropertiesParser implements
PropertiesParser {
* @param replacedPropertyKeys Already replaced property keys used
for tracking circular references
* @return Evaluated string
*/
- private String doParseNested(String input, Set<String>
replacedPropertyKeys) {
+ private String doParseNested(String prevKey, String input, Set<String>
replacedPropertyKeys) {
if (input == null) {
return null;
}
String answer = input;
Property property;
- while ((property = readProperty(answer)) != null) {
+ while ((property = readProperty(prevKey, answer)) != null) {
if (replacedPropertyKeys.contains(property.getKey())) {
// Check for circular references (skip optional)
boolean optional =
property.getKey().startsWith(OPTIONAL_TOKEN);
@@ -181,6 +183,12 @@ public class DefaultPropertiesParser implements
PropertiesParser {
}
}
+ if (propertiesComponent != null) {
+ // nested placeholder so update resolved property with new
value
+ String k = prevKey != null ? prevKey : property.getKey();
+ propertiesComponent.updateResolvedValue(k,
property.getValue(), null);
+ }
+
Set<String> newReplaced = new HashSet<>(replacedPropertyKeys);
newReplaced.add(property.getKey());
@@ -191,7 +199,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
}
String before = answer.substring(0, beginIndex);
String after = answer.substring(property.getEndIndex());
- String parsed = doParseNested(property.getValue(),
newReplaced);
+ String parsed = doParseNested(property.getKey(),
property.getValue(), newReplaced);
if (parsed != null) {
answer = before + parsed + after;
} else {
@@ -213,7 +221,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
* @param input Input string
* @return A property in the given string or {@code null} if not
found
*/
- private Property readProperty(String input) {
+ private Property readProperty(String prevKey, String input) {
// Find the index of the first valid suffix token
int suffix = getSuffixIndex(input);
@@ -232,7 +240,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
}
String key = input.substring(prefix + PREFIX_TOKEN.length(),
suffix);
- String value = getPropertyValue(key, input);
+ String value = getPropertyValue(prevKey, key, input);
return new Property(prefix, suffix + SUFFIX_TOKEN.length(), key,
value);
}
@@ -308,7 +316,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
* @param input Input string (used for exception message if value not
found)
* @return Value of the property with the given key
*/
- private String getPropertyValue(String key, String input) {
+ private String getPropertyValue(String prevKey, String key, String
input) {
if (key == null) {
return null;
}
@@ -326,7 +334,7 @@ public class DefaultPropertiesParser implements
PropertiesParser {
String remainder = StringHelper.after(key, ":");
boolean remainderOptional =
remainder.startsWith(OPTIONAL_TOKEN);
if (function.lookupFirst(remainder)) {
- String value = getPropertyValue(remainder, input);
+ String value = getPropertyValue(prevKey, remainder,
input);
if (value == null && (remainderOptional ||
function.optional(remainder))) {
return null;
}
@@ -366,6 +374,8 @@ public class DefaultPropertiesParser implements
PropertiesParser {
log.debug("Property with key [{}] applied by
function [{}] -> {}", key, function.getName(),
value);
}
+ String k = prevKey != null ? prevKey : key;
+ propertiesComponent.updateResolvedValue(k, value,
function.getName());
return value;
}
}
@@ -382,6 +392,13 @@ public class DefaultPropertiesParser implements
PropertiesParser {
if (value == null && defaultValue != null) {
log.debug("Property with key [{}] not found, using default
value: {}", key, defaultValue);
value = defaultValue;
+ for (PropertiesLookupListener listener :
propertiesComponent.getPropertiesLookupListeners()) {
+ try {
+ listener.onLookup(key, value, defaultValue, null);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
}
if (value == null) {
diff --git
a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
index 0cfa3746e72..698103884de 100644
---
a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
+++
b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
@@ -36,6 +36,7 @@ import org.apache.camel.spi.Configurer;
import org.apache.camel.spi.FactoryFinder;
import org.apache.camel.spi.LoadablePropertiesSource;
import org.apache.camel.spi.PropertiesFunction;
+import org.apache.camel.spi.PropertiesResolvedValue;
import org.apache.camel.spi.PropertiesSource;
import org.apache.camel.spi.PropertiesSourceFactory;
import org.apache.camel.spi.annotations.JdkService;
@@ -111,6 +112,7 @@ public class PropertiesComponent extends ServiceSupport
private final PropertiesLookup propertiesLookup = new
DefaultPropertiesLookup(this);
private final List<PropertiesLookupListener> propertiesLookupListeners =
new ArrayList<>();
private final PropertiesSourceFactory propertiesSourceFactory = new
DefaultPropertiesSourceFactory(this);
+ private final DefaultPropertiesLookupListener
defaultPropertiesLookupListener = new DefaultPropertiesLookupListener();
private final List<PropertiesSource> sources = new ArrayList<>();
private List<PropertiesLocation> locations = new ArrayList<>();
private String location;
@@ -128,6 +130,7 @@ public class PropertiesComponent extends ServiceSupport
private boolean autoDiscoverPropertiesSources = true;
public PropertiesComponent() {
+ addPropertiesLookupListener(defaultPropertiesLookupListener);
// include out of the box functions
addPropertiesFunction(new EnvPropertiesFunction());
addPropertiesFunction(new SysPropertiesFunction());
@@ -187,6 +190,15 @@ public class PropertiesComponent extends ServiceSupport
}
}
+ @Override
+ public Optional<PropertiesResolvedValue> getResolvedValue(String key) {
+ return
Optional.ofNullable(defaultPropertiesLookupListener.getProperty(key));
+ }
+
+ public void updateResolvedValue(String key, String newValue, String
newSource) {
+ defaultPropertiesLookupListener.updateValue(key, newValue, newSource);
+ }
+
@Override
public Properties loadProperties() {
// this method may be replaced by loadProperties(k -> true) but the
underlying sources
@@ -784,27 +796,27 @@ public class PropertiesComponent extends ServiceSupport
}
sources.sort(OrderedComparator.get());
- ServiceHelper.initService(sources, propertiesFunctionResolver);
+ ServiceHelper.initService(sources, propertiesFunctionResolver,
defaultPropertiesLookupListener);
}
@Override
protected void doBuild() throws Exception {
- ServiceHelper.buildService(sources, propertiesFunctionResolver);
+ ServiceHelper.buildService(sources, propertiesFunctionResolver,
defaultPropertiesLookupListener);
}
@Override
protected void doStart() throws Exception {
- ServiceHelper.startService(sources, propertiesFunctionResolver);
+ ServiceHelper.startService(sources, propertiesFunctionResolver,
defaultPropertiesLookupListener);
}
@Override
protected void doStop() throws Exception {
- ServiceHelper.stopService(sources, propertiesFunctionResolver);
+ ServiceHelper.stopService(sources, propertiesFunctionResolver,
defaultPropertiesLookupListener);
}
@Override
protected void doShutdown() throws Exception {
- ServiceHelper.stopAndShutdownServices(sources,
propertiesFunctionResolver);
+ ServiceHelper.stopAndShutdownServices(sources,
propertiesFunctionResolver, defaultPropertiesLookupListener);
}
private void addPropertiesLocationsAsPropertiesSource(PropertiesLocation
location, int order) {
diff --git
a/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
b/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
index 9b0884b3e67..2ebe943ee55 100644
---
a/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
+++
b/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
@@ -82,10 +82,28 @@ public class PropertiesDevConsole extends
AbstractDevConsole {
String k = entry.getKey().toString();
Object v = entry.getValue();
String loc = olp != null ? olp.getLocation(k) : null;
-
+ String originalValue = null;
+ String defaultValue = null;
+ String source = null;
+ var m = pc.getResolvedValue(k);
+ if (m.isPresent()) {
+ originalValue = m.get().originalValue();
+ defaultValue = m.get().defaultValue();
+ source = m.get().source();
+ v = m.get().value();
+ }
JsonObject jo = new JsonObject();
jo.put("key", k);
jo.put("value", v);
+ if (originalValue != null) {
+ jo.put("originalValue", originalValue);
+ }
+ if (defaultValue != null) {
+ jo.put("defaultValue", defaultValue);
+ }
+ if (source != null) {
+ jo.put("source", source);
+ }
if (loc != null) {
jo.put("location", loc);
jo.put("internal", isInternal(loc));
diff --git
a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentResolvedValueTest.java
b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentResolvedValueTest.java
new file mode 100644
index 00000000000..c7768d33412
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentResolvedValueTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class PropertiesComponentResolvedValueTest extends ContextTestSupport {
+
+ @Test
+ public void testResolved() {
+ org.apache.camel.spi.PropertiesComponent pc =
context.getPropertiesComponent();
+
+ Assertions.assertTrue(pc.getResolvedValue("unknown").isEmpty());
+ Assertions.assertTrue(pc.getResolvedValue("greeting").isPresent());
+ Assertions.assertTrue(pc.getResolvedValue("cool.end").isPresent());
+ Assertions.assertTrue(pc.getResolvedValue("place").isPresent());
+ Assertions.assertTrue(pc.getResolvedValue("myserver").isPresent());
+
+ // added initial via code
+ var p = pc.getResolvedValue("greeting").get();
+ Assertions.assertEquals("greeting", p.name());
+ Assertions.assertEquals("Hello World", p.originalValue());
+ Assertions.assertEquals("Hello World", p.value());
+ Assertions.assertEquals("Hi", p.defaultValue());
+ Assertions.assertEquals("InitialProperties", p.source());
+
+ // from properties file
+ p = pc.getResolvedValue("cool.end").get();
+ Assertions.assertEquals("cool.end", p.name());
+ Assertions.assertEquals("mock:result", p.originalValue());
+ Assertions.assertEquals("mock:result", p.value());
+ Assertions.assertNull(p.defaultValue());
+
Assertions.assertEquals("classpath:org/apache/camel/component/properties/myproperties.properties",
p.source());
+
+ // no source but using default value
+ p = pc.getResolvedValue("place").get();
+ Assertions.assertEquals("place", p.name());
+ Assertions.assertEquals("Paris", p.originalValue());
+ Assertions.assertEquals("Paris", p.value());
+ Assertions.assertEquals("Paris", p.defaultValue());
+ Assertions.assertNull(p.source());
+
+ // nested
+ p = pc.getResolvedValue("myserver").get();
+ Assertions.assertEquals("myserver", p.name());
+ Assertions.assertEquals("127.0.0.1", p.value());
+ Assertions.assertEquals("{{env:MY_SERVER:127.0.0.1}}",
p.originalValue());
+ Assertions.assertNull(p.defaultValue());
+ Assertions.assertEquals("env", p.source());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start")
+ .setBody(constant("{{greeting:Hi}}"))
+ .setHeader("bar", constant("{{?place:Paris}}"))
+ .setHeader("server", constant("{{myserver}}"))
+ .to("{{cool.end}}");
+ }
+ };
+ }
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+
context.getPropertiesComponent().setLocation("classpath:org/apache/camel/component/properties/myproperties.properties");
+ context.getPropertiesComponent().addInitialProperty("greeting", "Hello
World");
+ context.getPropertiesComponent().addInitialProperty("myserver",
"{{env:MY_SERVER:127.0.0.1}}");
+ return context;
+ }
+
+}
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationDevConsole.java
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationDevConsole.java
index e1a7dce07d7..aa88d984716 100644
---
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationDevConsole.java
+++
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationDevConsole.java
@@ -18,6 +18,7 @@ package org.apache.camel.main;
import java.util.Map;
+import org.apache.camel.spi.PropertiesComponent;
import org.apache.camel.spi.annotations.DevConsole;
import org.apache.camel.support.console.AbstractDevConsole;
import org.apache.camel.util.OrderedLocationProperties;
@@ -68,6 +69,8 @@ public class MainConfigurationDevConsole extends
AbstractDevConsole {
@Override
protected Map<String, Object> doCallJson(Map<String, Object> options) {
+ PropertiesComponent pc = getCamelContext().getPropertiesComponent();
+
JsonObject root = new JsonObject();
if (!startupConfiguration.isEmpty()) {
JsonArray arr = new JsonArray();
@@ -75,10 +78,25 @@ public class MainConfigurationDevConsole extends
AbstractDevConsole {
String k = entry.getKey().toString();
Object v = entry.getValue();
String loc = startupConfiguration.getLocation(k);
+ Object defaultValue = startupConfiguration.getDefaultValue(k);
JsonObject jo = new JsonObject();
jo.put("key", k);
jo.put("value", v);
+ if (defaultValue != null) {
+ jo.put("defaultValue", defaultValue);
+ }
+ // enrich if present
+ pc.getResolvedValue(k).ifPresent(r -> {
+ String ov = r.originalValue();
+ if (ov != null) {
+ jo.put("originalValue", ov);
+ }
+ String src = r.source();
+ if (src != null) {
+ jo.put("source", src);
+ }
+ });
if (loc != null) {
jo.put("location", loc);
jo.put("internal", isInternal(loc));
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProperties.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProperties.java
index 3da48a218bf..02bb13ceb90 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProperties.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProperties.java
@@ -28,6 +28,7 @@ import com.github.freva.asciitable.OverflowBehaviour;
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
import org.apache.camel.util.SensitiveUtils;
+import org.apache.camel.util.StringHelper;
import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
import picocli.CommandLine;
@@ -58,6 +59,9 @@ public class ListProperties extends ProcessWatchCommand {
@CommandLine.Option(names = { "--startup" }, description = "List only
startup configuration")
boolean startup;
+ @CommandLine.Option(names = { "--verbose" }, description = "Whether to
include more details")
+ boolean verbose;
+
@CommandLine.Option(names = { "--internal" }, description = "Whether to
include internal configuration")
boolean internal;
@@ -109,7 +113,13 @@ public class ListProperties extends ProcessWatchCommand {
value = "xxxxxx";
}
row.value = value;
+ value = jo.getString("originalValue");
+ if (mask &&
SensitiveUtils.containsSensitive(row.key)) {
+ value = "xxxxxx";
+ }
+ row.originalValue = value;
row.internalLoc =
jo.getBooleanOrDefault("internal", false);
+ row.source = jo.getString("source");
row.loc =
sanitizeLocation(jo.getString("location"));
boolean accept = internal || !row.internalLoc;
if (accept) {
@@ -132,12 +142,22 @@ public class ListProperties extends ProcessWatchCommand {
new
Column().header("KEY").dataAlign(HorizontalAlign.LEFT).maxWidth(50,
OverflowBehaviour.ELLIPSIS_RIGHT)
.with(r -> r.key),
new
Column().header("VALUE").dataAlign(HorizontalAlign.LEFT).maxWidth(80,
OverflowBehaviour.NEWLINE)
- .with(r -> "" + r.value))));
+ .with(r -> "" + r.value),
+ new
Column().header("FUNCTION").visible(verbose).dataAlign(HorizontalAlign.LEFT)
+ .maxWidth(50, OverflowBehaviour.ELLIPSIS_RIGHT)
+ .with(this::getFunction),
+ new Column().header("ORIGINAL
VALUE").visible(verbose).dataAlign(HorizontalAlign.LEFT)
+ .maxWidth(80, OverflowBehaviour.NEWLINE)
+ .with(r -> "" + r.originalValue))));
}
return 0;
}
+ protected String getFunction(Row r) {
+ return StringHelper.before(r.source, ":", r.source);
+ }
+
protected int sortRow(Row o1, Row o2) {
String s = sort;
int negate = 1;
@@ -162,6 +182,8 @@ public class ListProperties extends ProcessWatchCommand {
String name;
String key;
Object value;
+ Object originalValue;
+ String source;
String loc;
boolean internalLoc;
@@ -182,7 +204,7 @@ public class ListProperties extends ProcessWatchCommand {
loc = "camel-main";
} else if ("SYS".equals(loc)) {
loc = "JVM System Property";
- } else if ("ENV".equals(loc)) {
+ } else if ("ENV".equals(loc) || "env".equals(loc)) {
loc = "OS Environment Variable";
} else if ("arguments".equals(loc) || "CLI".equals(loc)) {
loc = "Command Line";