This is an automated email from the ASF dual-hosted git repository.
gtully 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 c5d872575e ARTEMIS-4256 - support removal of configuration via
properties
c5d872575e is described below
commit c5d872575e5ed08a3d5d13e6bcdac8eaf230e0b1
Author: Gary Tully <[email protected]>
AuthorDate: Thu May 4 15:50:40 2023 +0100
ARTEMIS-4256 - support removal of configuration via properties
---
.../api/config/ActiveMQDefaultConfiguration.java | 8 +++
.../core/config/impl/ConfigurationImpl.java | 76 +++++++++++++++++++++-
.../core/config/impl/ConfigurationImplTest.java | 42 ++++++++++++
docs/user-manual/en/configuration-index.md | 1 +
4 files changed, 124 insertions(+), 3 deletions(-)
diff --git
a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
index 05e8e7494d..69c1aba3c9 100644
---
a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
+++
b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
@@ -569,8 +569,12 @@ public final class ActiveMQDefaultConfiguration {
public static final String BROKER_PROPERTIES_KEY_SURROUND = "\"";
+ public static final String BROKER_PROPERTIES_REMOVE_VALUE = "-";
+
public static final String BROKER_PROPERTIES_KEY_SURROUND_PROPERTY =
"key.surround";
+ public static final String BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY =
"remove.value";
+
public static String DEFAULT_NETWORK_CHECK_LIST = null;
public static String DEFAULT_NETWORK_CHECK_URL_LIST = null;
@@ -1625,6 +1629,10 @@ public final class ActiveMQDefaultConfiguration {
return BROKER_PROPERTIES_KEY_SURROUND;
}
+ public static String getDefaultBrokerPropertiesRemoveValue() {
+ return BROKER_PROPERTIES_REMOVE_VALUE;
+ }
+
public static String getDefaultNetworkCheckList() {
return DEFAULT_NETWORK_CHECK_LIST;
}
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 37db97b804..6d2b006ce0 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
@@ -42,6 +42,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -379,6 +380,8 @@ public class ConfigurationImpl implements Configuration,
Serializable {
private String brokerPropertiesKeySurround =
ActiveMQDefaultConfiguration.getDefaultBrokerPropertiesKeySurround();
+ private String brokerPropertiesRemoveValue =
ActiveMQDefaultConfiguration.getDefaultBrokerPropertiesRemoveValue();
+
private String networkCheckList =
ActiveMQDefaultConfiguration.getDefaultNetworkCheckList();
private String networkURLList =
ActiveMQDefaultConfiguration.getDefaultNetworkCheckURLList();
@@ -502,6 +505,14 @@ public class ConfigurationImpl implements Configuration,
Serializable {
this.brokerPropertiesKeySurround = brokerPropertiesKeySurround;
}
+ public String getBrokerPropertiesRemoveValue() {
+ return brokerPropertiesRemoveValue;
+ }
+
+ public void setBrokerPropertiesRemoveValue(String
brokerPropertiesRemoveValue) {
+ this.brokerPropertiesRemoveValue = brokerPropertiesRemoveValue;
+ }
+
@Override
public Configuration parseProperties(String fileUrlToProperties) throws
Exception {
// system property overrides location of file(s)
@@ -588,7 +599,7 @@ public class ConfigurationImpl implements Configuration,
Serializable {
}
public void populateWithProperties(final Object target, final String
propsId, Map<String, Object> beanProperties) throws InvocationTargetException,
IllegalAccessException {
- CollectionAutoFillPropertiesUtil autoFillCollections = new
CollectionAutoFillPropertiesUtil();
+ CollectionAutoFillPropertiesUtil autoFillCollections = new
CollectionAutoFillPropertiesUtil(getBrokerPropertiesRemoveValue(beanProperties));
BeanUtilsBean beanUtils = new BeanUtilsBean(new ConvertUtilsBean(),
autoFillCollections) {
// override to treat missing properties as errors, not skip as the
default impl does
@Override
@@ -613,8 +624,38 @@ public class ConfigurationImpl implements Configuration,
Serializable {
}
logger.trace("resolved target, bean: {}, name: {}",
target.getClass(), name);
- // Declare local variables we will require
final String propName = resolver.getProperty(name); // Simple
name of target property
+ if (autoFillCollections.isRemoveValue(value)) {
+ logger.trace("removing from target, bean: {}, name: {}",
target.getClass(), name);
+
+ // we may do a further get but no longer want to reference
our nested collection stack
+ if (!autoFillCollections.collections.isEmpty()) {
+ autoFillCollections.collections.pop();
+ }
+ if (target instanceof Map) {
+ Map targetMap = (Map) target;
+ Iterator<Map.Entry<String, Object>> i =
targetMap.entrySet().iterator();
+ while (i.hasNext()) {
+ String key = i.next().getKey();
+ if (propName.equals(key)) {
+ i.remove();
+ break;
+ }
+ }
+ } else if (target instanceof Collection) {
+ try {
+ autoFillCollections.removeByNameProperty(propName,
(Collection) target);
+ } catch (NoSuchMethodException e) {
+ throw new InvocationTargetException(e, "Can only
remove named entries from collections or maps" + name + ", on: " + target);
+ }
+ } else {
+ throw new InvocationTargetException(null, "Can only
remove entries from collections or maps" + name + ", on: " + target);
+ }
+
+ logger.trace("removed from target, bean: {}, name: {}",
target.getClass(), name);
+ return;
+ }
+
Class<?> type = null; // Java type of
target property
final int index = resolver.getIndex(name); // Indexed
subscript value (if any)
final String key = resolver.getKey(name); // Mapped
key value (if any)
@@ -814,12 +855,20 @@ public class ConfigurationImpl implements Configuration,
Serializable {
private String getBrokerPropertiesKeySurround(Map<String, Object>
propertiesToApply) {
if
(propertiesToApply.containsKey(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY))
{
- return
String.valueOf(propertiesToApply.get(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY));
+ return
String.valueOf(propertiesToApply.remove(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY));
} else {
return System.getProperty(getSystemPropertyPrefix() +
ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY,
getBrokerPropertiesKeySurround());
}
}
+ private String getBrokerPropertiesRemoveValue(Map<String, Object>
propertiesToApply) {
+ if
(propertiesToApply.containsKey(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY))
{
+ return
String.valueOf(propertiesToApply.remove(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY));
+ } else {
+ return System.getProperty(getSystemPropertyPrefix() +
ActiveMQDefaultConfiguration.BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY,
getBrokerPropertiesRemoveValue());
+ }
+ }
+
@Override
public boolean isClustered() {
return !getClusterConfigurations().isEmpty();
@@ -3077,8 +3126,13 @@ public class ConfigurationImpl implements Configuration,
Serializable {
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{};
final Stack<Pair<String, Object>> collections = new Stack<>();
+ final String removeValue;
private BeanUtilsBean beanUtilsBean;
+ CollectionAutoFillPropertiesUtil(String brokerPropertiesRemoveValue) {
+ this.removeValue = brokerPropertiesRemoveValue;
+ }
+
@Override
public void setProperty(final Object bean, final String name, final
Object value) throws InvocationTargetException, IllegalAccessException,
NoSuchMethodException {
// any set will invalidate our collections stack
@@ -3144,6 +3198,18 @@ public class ConfigurationImpl implements Configuration,
Serializable {
return null;
}
+ private Object removeByNameProperty(String key, Collection collection)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
{
+ // locate on name property, may be a SimpleString
+ for (Object candidate : collection) {
+ Object candidateName = getProperty(candidate, "name");
+ if (candidateName != null && key.equals(candidateName.toString()))
{
+ collection.remove(candidate);
+ break;
+ }
+ }
+ return null;
+ }
+
// allow finding beans in collections via name() such that a mapped key
(key)
// can be used to access and *not* auto create entries
@Override
@@ -3257,6 +3323,10 @@ public class ConfigurationImpl implements Configuration,
Serializable {
// we want type conversion
this.beanUtilsBean = beanUtilsBean;
}
+
+ public boolean isRemoveValue(Object value) {
+ return removeValue != null && removeValue.equals(value);
+ }
}
private static class SurroundResolver extends DefaultResolver {
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 064b552ddd..018ac4183d 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
@@ -967,6 +967,46 @@ public class ConfigurationImplTest extends
ActiveMQTestBase {
Assert.assertEquals(false,
configuration.getAddressConfigurations().get(0).getQueueConfigs().get(0).isDurable());
}
+ @Test
+ public void testAddressRemovalViaProperties() throws Throwable {
+ ConfigurationImpl configuration = new ConfigurationImpl();
+
+ Properties properties = new Properties();
+
+
properties.put("addressConfigurations.\"LB.TEST\".queueConfigs.\"LB.TEST\".routingType",
"ANYCAST");
+ configuration.parsePrefixedProperties(properties, null);
+
+ Assert.assertEquals(1, configuration.getAddressConfigurations().size());
+ Assert.assertEquals(1,
configuration.getAddressConfigurations().get(0).getQueueConfigs().size());
+ Assert.assertTrue(configuration.getStatus().contains("\"errors\":[]"));
+
+ properties.clear();
+ properties.put("addressConfigurations.\"LB.TEST\"", "-");
+ configuration.parsePrefixedProperties(properties, null);
+
+ Assert.assertEquals(0, configuration.getAddressConfigurations().size());
+ Assert.assertTrue(configuration.getStatus().contains("\"errors\":[]"));
+ }
+
+ @Test
+ public void testRoleRemovalViaCustomRemoveProperties() throws Throwable {
+ ConfigurationImpl configuration = new ConfigurationImpl();
+
+ Properties properties = new Properties();
+
+ properties.put("securityRoles.TEST.users.send", "true");
+ configuration.parsePrefixedProperties(properties, null);
+ Assert.assertEquals(1, configuration.getSecurityRoles().size());
+ Assert.assertTrue(configuration.getStatus().contains("\"errors\":[]"));
+
+ properties.clear();
+
properties.put(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY,
"^");
+ properties.put("securityRoles.TEST", "^");
+ configuration.parsePrefixedProperties(properties, null);
+ Assert.assertEquals(0, configuration.getSecurityRoles().size());
+ Assert.assertTrue(configuration.getStatus().contains("\"errors\":[]"));
+ }
+
@Test
public void testIDCacheSizeViaProperties() throws Throwable {
ConfigurationImpl configuration = new ConfigurationImpl();
@@ -1639,6 +1679,8 @@ public class ConfigurationImplTest extends
ActiveMQTestBase {
Assert.assertEquals(SimpleString.toSimpleString("sharedExpiry"),
configuration.getAddressSettings().get("#").getExpiryAddress());
Assert.assertEquals(SimpleString.toSimpleString("important"),
configuration.getAddressSettings().get("NeedToTrackExpired").getExpiryAddress());
Assert.assertEquals(SimpleString.toSimpleString("moreImportant"),
configuration.getAddressSettings().get("Name.With.Dots").getExpiryAddress());
+
+ Assert.assertTrue(configuration.getStatus().contains("\"errors\":[]"));
}
@Test
diff --git a/docs/user-manual/en/configuration-index.md
b/docs/user-manual/en/configuration-index.md
index 296552bf53..8f522934eb 100644
--- a/docs/user-manual/en/configuration-index.md
+++ b/docs/user-manual/en/configuration-index.md
@@ -91,6 +91,7 @@ reflect the camelCase java naming convention.
Collections need some special treatment to allow additions and reference. We
utilise the name attribute of configuration
entities to find existing entries and when populating new entities, we set the
name to match the requested key.
+Removal of configuration from named collections is supported by setting a key
value to "-". The remove match value can be configured with a property key
"remove.value".
For example, a properties file containing: