This is an automated email from the ASF dual-hosted git repository.
robbie pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/main by this push:
new 4d8ccc4b2f ARTEMIS-4955 Support broker properties from JSON files
4d8ccc4b2f is described below
commit 4d8ccc4b2f31428b9caddad20643430e30c0cf32
Author: Domenico Francesco Bruscino <[email protected]>
AuthorDate: Fri May 17 09:38:15 2024 +0200
ARTEMIS-4955 Support broker properties from JSON files
---
.../core/config/impl/ConfigurationImpl.java | 73 ++++++++--
.../core/config/impl/ConfigurationImplTest.java | 162 +++++++++++++++++++++
2 files changed, 219 insertions(+), 16 deletions(-)
diff --git
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
index 9f4ac3ccfb..2a532d16bb 100644
---
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
+++
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
@@ -18,14 +18,16 @@ package org.apache.activemq.artemis.core.config.impl;
import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;
-import java.io.BufferedInputStream;
+import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
+import java.io.Reader;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.invoke.MethodHandles;
@@ -113,6 +115,7 @@ import
org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings;
import org.apache.activemq.artemis.json.JsonArrayBuilder;
import org.apache.activemq.artemis.json.JsonObject;
import org.apache.activemq.artemis.json.JsonObjectBuilder;
+import org.apache.activemq.artemis.json.JsonValue;
import org.apache.activemq.artemis.utils.ByteUtil;
import org.apache.activemq.artemis.utils.ClassloadingUtil;
import org.apache.activemq.artemis.utils.Env;
@@ -559,31 +562,20 @@ public class ConfigurationImpl implements Configuration,
Serializable {
fileUrlToProperties = resolvePropertiesSources(fileUrlToProperties);
if (fileUrlToProperties != null) {
for (String fileUrl : fileUrlToProperties.split(",")) {
- Properties brokerProperties = new InsertionOrderedProperties();
if (fileUrl.endsWith("/")) {
// treat as a directory and parse every property file in
alphabetical order
File dir = new File(fileUrl);
if (dir.exists()) {
- String[] files = dir.list((file, s) ->
s.endsWith(".properties"));
+ String[] files = dir.list((file, s) -> s.endsWith(".json")
|| s.endsWith(".properties"));
if (files != null && files.length > 0) {
Arrays.sort(files);
for (String fileName : files) {
- try (FileInputStream fileInputStream = new
FileInputStream(new File(dir, fileName));
- BufferedInputStream reader = new
BufferedInputStream(fileInputStream)) {
- brokerProperties.clear();
- brokerProperties.load(reader);
- parsePrefixedProperties(this, fileName,
brokerProperties, null);
- }
+ parseFileProperties(new File(dir, fileName));
}
}
}
} else {
- File file = new File(fileUrl);
- try (FileInputStream fileInputStream = new
FileInputStream(file);
- BufferedInputStream reader = new
BufferedInputStream(fileInputStream)) {
- brokerProperties.load(reader);
- parsePrefixedProperties(this, file.getName(),
brokerProperties, null);
- }
+ parseFileProperties(new File(fileUrl));
}
}
}
@@ -591,6 +583,20 @@ public class ConfigurationImpl implements Configuration,
Serializable {
return this;
}
+ private void parseFileProperties(File file) throws Exception {
+ InsertionOrderedProperties brokerProperties = new
InsertionOrderedProperties();
+ try (FileReader fileReader = new FileReader(file);
+ BufferedReader reader = new BufferedReader(fileReader)) {
+ if (file.getName().endsWith(".json")) {
+ brokerProperties.loadJson(reader);
+ } else {
+ brokerProperties.load(reader);
+ }
+ }
+
+ parsePrefixedProperties(this, file.getName(), brokerProperties, null);
+ }
+
public void parsePrefixedProperties(Properties properties, String prefix)
throws Exception {
parsePrefixedProperties(this, "system-" + prefix, properties, prefix);
}
@@ -3691,5 +3697,40 @@ public class ConfigurationImpl implements Configuration,
Serializable {
public void clear() {
orderedMap.clear();
}
+
+ public synchronized boolean loadJson(Reader reader) throws IOException {
+ JsonObject jsonObject = JsonLoader.readObject(reader);
+
+ loadJsonObject("", jsonObject);
+
+ return true;
+ }
+
+ private void loadJsonObject(String parentKey, JsonObject jsonObject) {
+
jsonObject.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(jsonEntry
-> {
+ JsonValue jsonValue = jsonEntry.getValue();
+ JsonValue.ValueType jsonValueType = jsonValue.getValueType();
+ String jsonKey = jsonEntry.getKey();
+ if (jsonKey.contains(".")) {
+ jsonKey = "\"" + jsonKey + "\"";
+ }
+ String propertyKey = parentKey + jsonKey;
+ switch (jsonValueType) {
+ case OBJECT:
+ loadJsonObject(propertyKey + ".", jsonValue.asJsonObject());
+ break;
+ case STRING:
+ put(propertyKey, jsonObject.getString(jsonKey));
+ break;
+ case NUMBER:
+ case TRUE:
+ case FALSE:
+ put(propertyKey, jsonValue.toString());
+ break;
+ default:
+ throw new IllegalStateException("JSON value type not
supported: " + jsonValueType);
+ }
+ });
+ }
}
}
diff --git
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java
index 43a1ac25e7..dacb05e892 100644
---
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java
+++
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java
@@ -28,12 +28,15 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
+import java.io.StringReader;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
@@ -93,7 +96,10 @@ import
org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy;
import org.apache.activemq.artemis.core.settings.impl.DeletionPolicy;
import org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings;
import
org.apache.activemq.artemis.core.settings.impl.SlowConsumerThresholdMeasurementUnit;
+import org.apache.activemq.artemis.json.JsonObject;
import org.apache.activemq.artemis.logs.AssertionLoggerHandler;
+import org.apache.activemq.artemis.json.JsonObjectBuilder;
+import org.apache.activemq.artemis.utils.JsonLoader;
import org.apache.activemq.artemis.utils.RandomUtil;
import org.apache.activemq.artemis.utils.critical.CriticalAnalyzerPolicy;
import org.apache.commons.lang3.ClassUtils;
@@ -1912,6 +1918,162 @@ public class ConfigurationImplTest extends
AbstractConfigurationTestBase {
assertEquals(CriticalAnalyzerPolicy.SHUTDOWN,
configuration.getCriticalAnalyzerPolicy());
}
+ @Test
+ public void testJsonInsertionOrderedProperties() throws Exception {
+ ConfigurationImpl.InsertionOrderedProperties properties =
+ new ConfigurationImpl.InsertionOrderedProperties();
+
+ JsonObject configJsonObject = buildSimpleConfigJsonObject();
+ try (StringReader stringReader = new
StringReader(configJsonObject.toString())) {
+ properties.loadJson(stringReader);
+ }
+
+ List<String> keys = new ArrayList<>();
+ properties.entrySet().forEach(entry -> keys.add((String)
entry.getKey()));
+
+ List<String> sortedKeys =
keys.stream().sorted().collect(Collectors.toList());
+ for (int i = 0; i < sortedKeys.size(); i++) {
+ assertEquals(i, keys.indexOf(sortedKeys.get(i)));
+ }
+ }
+
+ @Test
+ public void testTextPropertiesReaderFromFile() throws Exception {
+ List<String> textProperties = buildSimpleConfigTextList();
+ File tmpFile = File.createTempFile("text-props-test", "",
temporaryFolder);
+ try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
+ PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
+ for (String textProperty : textProperties) {
+ printWriter.println(textProperty);
+ }
+ }
+
+ ConfigurationImpl configuration = new ConfigurationImpl();
+ configuration.parseProperties(tmpFile.getAbsolutePath());
+
+ testSimpleConfig(configuration);
+ }
+
+ @Test
+ public void testJsonPropertiesReaderFromFile() throws Exception {
+
+ JsonObject configJsonObject = buildSimpleConfigJsonObject();
+ File tmpFile = File.createTempFile("json-props-test", ".json",
temporaryFolder);
+ try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
+ PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
+ printWriter.write(configJsonObject.toString());
+ }
+
+ ConfigurationImpl configuration = new ConfigurationImpl();
+ configuration.parseProperties(tmpFile.getAbsolutePath());
+
+ testSimpleConfig(configuration);
+ }
+
+ @Test
+ public void testInvalidJsonPropertiesReaderFromFile() throws Exception {
+
+ File tmpFile = File.createTempFile("json-props-test", ".json",
temporaryFolder);
+ try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
+ PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
+ printWriter.write("INVALID_JSON");
+ }
+
+ ConfigurationImpl configuration = new ConfigurationImpl();
+
+ try {
+ configuration.parseProperties(tmpFile.getAbsolutePath());
+ fail("Expected JSON parsing exception.");
+ } catch (Exception e) {
+ }
+ }
+
+ private JsonObject buildSimpleConfigJsonObject() {
+ JsonObjectBuilder configObjectBuilder = JsonLoader.createObjectBuilder();
+ {
+ configObjectBuilder.add("globalMaxSize", "25K");
+ configObjectBuilder.add("gracefulShutdownEnabled", true);
+ configObjectBuilder.add("securityEnabled", false);
+ configObjectBuilder.add("maxRedeliveryRecords", 123);
+
+ JsonObjectBuilder addressConfigObjectBuilder =
JsonLoader.createObjectBuilder();
+ {
+ JsonObjectBuilder lbaObjectBuilder =
JsonLoader.createObjectBuilder();
+ {
+ JsonObjectBuilder queueConfigBuilder =
JsonLoader.createObjectBuilder();
+ {
+ JsonObjectBuilder lbqObjectBuilder =
JsonLoader.createObjectBuilder();
+ {
+ lbqObjectBuilder.add("routingType", "ANYCAST");
+ lbqObjectBuilder.add("durable", false);
+ }
+ queueConfigBuilder.add("LB.TEST", lbqObjectBuilder.build());
+
+ JsonObjectBuilder myqObjectBuilder =
JsonLoader.createObjectBuilder();
+ {
+ myqObjectBuilder.add("routingType", "ANYCAST");
+ myqObjectBuilder.add("durable", false);
+ }
+ queueConfigBuilder.add("my queue", myqObjectBuilder.build());
+ }
+ lbaObjectBuilder.add("queueConfigs",
queueConfigBuilder.build());
+ }
+ addressConfigObjectBuilder.add("LB.TEST",
lbaObjectBuilder.build());
+ }
+ configObjectBuilder.add("addressConfigurations",
addressConfigObjectBuilder.build());
+
+ JsonObjectBuilder clusterConfigObjectBuilder =
JsonLoader.createObjectBuilder();
+ {
+ JsonObjectBuilder ccObjectBuilder =
JsonLoader.createObjectBuilder();
+ {
+ ccObjectBuilder.add("name", "cc");
+ ccObjectBuilder.add("messageLoadBalancingType",
"OFF_WITH_REDISTRIBUTION");
+ }
+ clusterConfigObjectBuilder.add("cc", ccObjectBuilder.build());
+ }
+ configObjectBuilder.add("clusterConfigurations",
clusterConfigObjectBuilder.build());
+
+ configObjectBuilder.add("criticalAnalyzerPolicy", "SHUTDOWN");
+ }
+
+ return configObjectBuilder.build();
+ }
+
+ private List<String> buildSimpleConfigTextList() {
+ List<String> textProperties = new ArrayList<>();
+
textProperties.add("addressConfigurations.\"LB.TEST\".queueConfigs.\"LB.TEST\".routingType=ANYCAST");
+
textProperties.add("addressConfigurations.\"LB.TEST\".queueConfigs.\"LB.TEST\".durable=false");
+ textProperties.add("addressConfigurations.\"LB.TEST\".queueConfigs.my\\
queue.routingType=ANYCAST");
+ textProperties.add("addressConfigurations.\"LB.TEST\".queueConfigs.my\\
queue.durable=false");
+ textProperties.add("globalMaxSize=25K");
+ textProperties.add("gracefulShutdownEnabled=true");
+ textProperties.add("securityEnabled=false");
+ textProperties.add("maxRedeliveryRecords=123");
+ textProperties.add("clusterConfigurations.cc.name=cc");
+
textProperties.add("clusterConfigurations.cc.messageLoadBalancingType=OFF_WITH_REDISTRIBUTION");
+ textProperties.add("criticalAnalyzerPolicy=SHUTDOWN");
+
+ return textProperties;
+ }
+
+ private void testSimpleConfig(Configuration configuration) {
+ assertEquals(25 * 1024, configuration.getGlobalMaxSize());
+ assertEquals(true, configuration.isGracefulShutdownEnabled());
+ assertEquals(false, configuration.isSecurityEnabled());
+ assertEquals(123, configuration.getMaxRedeliveryRecords());
+
+ assertEquals(1, configuration.getAddressConfigurations().size());
+ assertEquals(2,
configuration.getAddressConfigurations().get(0).getQueueConfigs().size());
+ assertEquals(SimpleString.of("LB.TEST"),
configuration.getAddressConfigurations().get(0).getQueueConfigs().get(0).getAddress());
+ assertEquals(false,
configuration.getAddressConfigurations().get(0).getQueueConfigs().get(0).isDurable());
+ assertEquals(SimpleString.of("my queue"),
configuration.getAddressConfigurations().get(0).getQueueConfigs().get(1).getAddress());
+ assertEquals(false,
configuration.getAddressConfigurations().get(0).getQueueConfigs().get(1).isDurable());
+
+ assertEquals("cc",
configuration.getClusterConfigurations().get(0).getName());
+ assertEquals(MessageLoadBalancingType.OFF_WITH_REDISTRIBUTION,
configuration.getClusterConfigurations().get(0).getMessageLoadBalancingType());
+ assertEquals(CriticalAnalyzerPolicy.SHUTDOWN,
configuration.getCriticalAnalyzerPolicy());
+ }
+
@Test
public void testPropertiesReaderRespectsOrderFromFile() throws Exception {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact