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 10d93d9  ARTEMIS-3627 - support broker.properties for augmenting or 
supplying additional configuration via nested properties of the internal 
configuratinimpl bean - elements with a name attribute can be configured in 
collections, the type inferred by the add singular fluent api
10d93d9 is described below

commit 10d93d9c92f1b0f276c88a8b782152af596cd7da
Author: gtully <gary.tu...@gmail.com>
AuthorDate: Fri Jan 7 17:50:03 2022 +0000

    ARTEMIS-3627 - support broker.properties for augmenting or supplying 
additional configuration via nested properties of the internal configuratinimpl 
bean - elements with a name attribute can be configured in collections, the 
type inferred by the add singular fluent api
---
 .../apache/activemq/artemis/cli/commands/Run.java  |  15 +-
 .../org/apache/activemq/cli/test/ArtemisTest.java  |  34 +++
 artemis-cli/src/test/resources/broker.properties   |  19 ++
 .../api/config/ActiveMQDefaultConfiguration.java   |  10 +
 .../artemis/api/core/TransportConfiguration.java   |   4 +
 .../artemis/core/config/Configuration.java         |   5 +-
 .../AMQPBrokerConnectConfiguration.java            |  13 +-
 .../AMQPBrokerConnectionElement.java               |  11 +
 .../core/config/impl/ConfigurationImpl.java        | 282 ++++++++++++++++++++-
 .../core/config/impl/FileConfiguration.java        |   2 -
 .../deployers/impl/FileConfigurationParser.java    |   4 +-
 .../artemis/core/server/ActiveMQServer.java        |   3 +
 .../core/server/embedded/EmbeddedActiveMQ.java     |   8 +
 .../core/server/impl/ActiveMQServerImpl.java       |  10 +-
 .../core/settings/impl/ResourceLimitSettings.java  |   4 +
 .../core/config/impl/ConfigurationImplTest.java    | 123 ++++++++-
 .../server/config/JMSServerPropertyConfigTest.java |  87 +++++++
 .../src/test/resources/broker.properties           |  18 ++
 18 files changed, 625 insertions(+), 27 deletions(-)

diff --git 
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java 
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java
index b594e37..dd00eb5 100644
--- 
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java
+++ 
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java
@@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import io.airlift.airline.Command;
 import io.airlift.airline.Option;
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
 import org.apache.activemq.artemis.api.core.Pair;
 import org.apache.activemq.artemis.cli.Artemis;
 import org.apache.activemq.artemis.cli.commands.tools.LockAbstract;
@@ -47,6 +48,9 @@ public class Run extends LockAbstract {
    @Option(name = "--allow-kill", description = "This will allow the server to 
kill itself. Useful for tests (failover tests for instance)")
    boolean allowKill;
 
+   @Option(name = "--properties", description = "A file url to a properties 
file that is applied to the server's internal ConfigurationImpl bean")
+   String properties;
+
    private static boolean embedded = false;
 
    public static final ReusableLatch latchRunning = new ReusableLatch(0);
@@ -112,6 +116,14 @@ public class Run extends LockAbstract {
 
          server.createComponents();
          server.getServer().registerActivationFailureListener(exception -> 
serverActivationFailed.set(exception));
+
+         if (properties == null) {
+            File propertiesFileFromEtc = new File(getBrokerEtc(), 
ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME);
+            if (propertiesFileFromEtc.exists()) {
+               properties = propertiesFileFromEtc.getAbsolutePath();
+            }
+         }
+         server.getServer().setProperties(properties);
          server.start();
          server.getServer().addExternalComponent(managementContext, false);
 
@@ -121,7 +133,7 @@ public class Run extends LockAbstract {
 
          for (ComponentDTO componentDTO : broker.components) {
             Class clazz = 
this.getClass().getClassLoader().loadClass(componentDTO.componentClassName);
-            ExternalComponent component = (ExternalComponent) 
clazz.newInstance();
+            ExternalComponent component = (ExternalComponent) 
clazz.getDeclaredConstructor(null).newInstance();
             component.configure(componentDTO, getBrokerInstance(), 
getBrokerHome());
             server.getServer().addExternalComponent(component, true);
             assert component.isStarted();
@@ -129,6 +141,7 @@ public class Run extends LockAbstract {
       } catch (Throwable t) {
          t.printStackTrace();
          serverActivationFailed.set(t);
+         latchRunning.countDown();
       }
 
       if (serverActivationFailed.get() != null) {
diff --git 
a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java 
b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
index 753f3f4..6020f78 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
@@ -39,6 +39,7 @@ import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -1921,6 +1922,39 @@ public class ArtemisTest extends CliTestBase {
    }
 
    @Test
+   public void testRunPropertiesArgumentSetsAcceptorPort() throws Exception {
+      File instanceFile = new File(temporaryFolder.getRoot(), 
"testRunPropertiesArgumentSetsAcceptorPort");
+      setupAuth(instanceFile);
+      Run.setEmbedded(true);
+      Artemis.main("create", instanceFile.getAbsolutePath(), "--silent", 
"--no-fsync", "--no-autotune", "--no-web", "--require-login");
+      System.setProperty("artemis.instance", instanceFile.getAbsolutePath());
+
+      // configure
+      URL brokerPropertiesFromClasspath = 
this.getClass().getClassLoader().getResource(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME);
+      Artemis.internalExecute("run", "--properties", new 
File(brokerPropertiesFromClasspath.toURI()).getAbsolutePath());
+
+      // verify
+      try (ActiveMQConnectionFactory cf = new 
ActiveMQConnectionFactory("tcp://localhost:61618"); Connection connection = 
cf.createConnection("admin", "admin");) {
+         connection.start();
+      } finally {
+         stopServer();
+      }
+   }
+
+   @Test
+   public void testRunPropertiesDudArgument() throws Exception {
+      File instanceFile = new File(temporaryFolder.getRoot(), 
"testRunPropertiesDudArgument");
+      setupAuth(instanceFile);
+      Run.setEmbedded(true);
+      Artemis.main("create", instanceFile.getAbsolutePath(), "--silent", 
"--no-fsync", "--no-autotune", "--no-web", "--require-login");
+      System.setProperty("artemis.instance", instanceFile.getAbsolutePath());
+
+      // verify error
+      Object ret = Artemis.internalExecute("run", "--properties", 
"https://www.apache.org";);
+      assertTrue(ret instanceof IllegalStateException);
+   }
+
+   @Test
    public void testVersionCommand() throws Exception {
       TestActionContext context = new TestActionContext();
       PrintVersion printVersion = new PrintVersion();
diff --git a/artemis-cli/src/test/resources/broker.properties 
b/artemis-cli/src/test/resources/broker.properties
new file mode 100644
index 0000000..4f6c2a1
--- /dev/null
+++ b/artemis-cli/src/test/resources/broker.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+name=ConfiguredViaProperties
+acceptorConfigurations.artemis.params.port=61618
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 092887e..f56d443 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
@@ -557,6 +557,12 @@ public final class ActiveMQDefaultConfiguration {
 
    public static final String DEFAULT_SYSTEM_PROPERTY_PREFIX = "brokerconfig.";
 
+   public static final String BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME = 
"broker.properties";
+
+   public static final String BROKER_PROPERTIES_KEY_SURROUND = "\"";
+
+   public static final String BROKER_PROPERTIES_KEY_SURROUND_PROPERTY = 
"key.surround";
+
    public static String DEFAULT_NETWORK_CHECK_LIST = null;
 
    public static String DEFAULT_NETWORK_CHECK_URL_LIST = null;
@@ -1587,6 +1593,10 @@ public final class ActiveMQDefaultConfiguration {
       return DEFAULT_SYSTEM_PROPERTY_PREFIX;
    }
 
+   public static String getDefaultBrokerPropertiesKeySurround() {
+      return BROKER_PROPERTIES_KEY_SURROUND;
+   }
+
    public static String getDefaultNetworkCheckList() {
       return DEFAULT_NETWORK_CHECK_LIST;
    }
diff --git 
a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TransportConfiguration.java
 
b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TransportConfiguration.java
index 2d9f415..84d7a8a 100644
--- 
a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TransportConfiguration.java
+++ 
b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TransportConfiguration.java
@@ -164,6 +164,10 @@ public class TransportConfiguration implements 
Serializable {
       return name;
    }
 
+   public void setName(String name) {
+      this.name = name;
+   }
+
    /**
     * Returns the class name of ConnectorFactory being used by this 
TransportConfiguration
     *
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
index a67d09b..8cc7d48 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
@@ -20,7 +20,6 @@ import java.io.File;
 import java.net.URL;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
@@ -87,9 +86,7 @@ public interface Configuration {
     */
    String getSystemPropertyPrefix();
 
-   Configuration parseSystemProperties() throws Exception;
-
-   Configuration parseSystemProperties(Properties properties) throws Exception;
+   Configuration parseProperties(String optionalUrlToPropertiesFile) throws 
Exception;
 
    boolean isCriticalAnalyzer();
 
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectConfiguration.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectConfiguration.java
index 25b5309..0dbdc56 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectConfiguration.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectConfiguration.java
@@ -31,16 +31,17 @@ public class AMQPBrokerConnectConfiguration extends 
BrokerConnectConfiguration {
 
    List<TransportConfiguration> transportConfigurations;
 
-   List<AMQPBrokerConnectionElement> connectionElements;
+   List<AMQPBrokerConnectionElement> connectionElements = new ArrayList<>();
+
+   public AMQPBrokerConnectConfiguration() {
+      super(null, null);
+   }
 
    public AMQPBrokerConnectConfiguration(String name, String uri) {
       super(name, uri);
    }
 
    public AMQPBrokerConnectConfiguration 
addElement(AMQPBrokerConnectionElement amqpBrokerConnectionElement) {
-      if (connectionElements == null) {
-         connectionElements = new ArrayList<>();
-      }
       amqpBrokerConnectionElement.setParent(this);
 
 
@@ -53,6 +54,10 @@ public class AMQPBrokerConnectConfiguration extends 
BrokerConnectConfiguration {
       return this;
    }
 
+   public AMQPBrokerConnectConfiguration 
addConnectionElement(AMQPMirrorBrokerConnectionElement 
amqpBrokerConnectionElement) {
+      return addElement(amqpBrokerConnectionElement);
+   }
+
    public List<AMQPBrokerConnectionElement> getConnectionElements() {
       return connectionElements;
    }
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectionElement.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectionElement.java
index f2a174f..89851c6 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectionElement.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPBrokerConnectionElement.java
@@ -23,6 +23,7 @@ import 
org.apache.activemq.artemis.core.config.WildcardConfiguration;
 import org.apache.activemq.artemis.core.postoffice.impl.AddressImpl;
 
 public class AMQPBrokerConnectionElement implements Serializable {
+   String name;
    SimpleString matchAddress;
    SimpleString queueName;
    AMQPBrokerConnectionAddressType type;
@@ -84,4 +85,14 @@ public class AMQPBrokerConnectionElement implements 
Serializable {
       this.type = type;
       return this;
    }
+
+
+   public String getName() {
+      return name;
+   }
+
+   public void setName(String name) {
+      this.name = name;
+   }
+
 }
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 4abd5a8..3c13f70 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
@@ -16,21 +16,27 @@
  */
 package org.apache.activemq.artemis.core.config.impl;
 
+import java.beans.PropertyDescriptor;
+import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.PrintWriter;
 import java.io.Serializable;
 import java.io.StringWriter;
 import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.URI;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -38,12 +44,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.Stack;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
 import org.apache.activemq.artemis.api.core.BroadcastGroupConfiguration;
 import org.apache.activemq.artemis.api.core.DiscoveryGroupConfiguration;
+import org.apache.activemq.artemis.api.core.Pair;
 import org.apache.activemq.artemis.api.core.QueueConfiguration;
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.TransportConfiguration;
@@ -65,6 +73,8 @@ import 
org.apache.activemq.artemis.core.config.WildcardConfiguration;
 import org.apache.activemq.artemis.core.config.ha.ReplicaPolicyConfiguration;
 import 
org.apache.activemq.artemis.core.config.ha.ReplicatedPolicyConfiguration;
 import 
org.apache.activemq.artemis.core.config.storage.DatabaseStorageConfiguration;
+import 
org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
+import 
org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
 import org.apache.activemq.artemis.core.server.JournalType;
@@ -89,7 +99,14 @@ import 
org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings;
 import org.apache.activemq.artemis.utils.Env;
 import org.apache.activemq.artemis.utils.ObjectInputStreamWithClassLoader;
 import org.apache.activemq.artemis.utils.critical.CriticalAnalyzerPolicy;
-import org.apache.activemq.artemis.utils.uri.BeanSupport;
+import 
org.apache.activemq.artemis.utils.uri.FluentPropertyBeanIntrospectorWithIgnores;
+import org.apache.commons.beanutils.BeanUtilsBean;
+import org.apache.commons.beanutils.ConvertUtilsBean;
+import org.apache.commons.beanutils.Converter;
+import org.apache.commons.beanutils.MappedPropertyDescriptor;
+import org.apache.commons.beanutils.MethodUtils;
+import org.apache.commons.beanutils.PropertyUtilsBean;
+import org.apache.commons.beanutils.expression.DefaultResolver;
 import org.jboss.logging.Logger;
 
 public class ConfigurationImpl implements Configuration, Serializable {
@@ -338,6 +355,8 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
 
    private String systemPropertyPrefix = 
ActiveMQDefaultConfiguration.getDefaultSystemPropertyPrefix();
 
+   private String brokerPropertiesKeySurround = 
ActiveMQDefaultConfiguration.getDefaultBrokerPropertiesKeySurround();
+
    private String networkCheckList = 
ActiveMQDefaultConfiguration.getDefaultNetworkCheckList();
 
    private String networkURLList = 
ActiveMQDefaultConfiguration.getDefaultNetworkCheckURLList();
@@ -429,31 +448,73 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
       return systemPropertyPrefix;
    }
 
+   public String getBrokerPropertiesKeySurround() {
+      return brokerPropertiesKeySurround;
+   }
+
+   public void setBrokerPropertiesKeySurround(String 
brokerPropertiesKeySurround) {
+      this.brokerPropertiesKeySurround = brokerPropertiesKeySurround;
+   }
+
    @Override
-   public Configuration parseSystemProperties() throws Exception {
-      parseSystemProperties(System.getProperties());
+   public Configuration parseProperties(String fileUrlToProperties) throws 
Exception {
+      // system property overrides
+      fileUrlToProperties = 
System.getProperty(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME,
 fileUrlToProperties);
+      if (fileUrlToProperties != null) {
+         Properties brokerProperties = new Properties();
+         try (FileInputStream fileInputStream = new 
FileInputStream(fileUrlToProperties); BufferedInputStream reader = new 
BufferedInputStream(fileInputStream)) {
+            brokerProperties.load(reader);
+            parsePrefixedProperties(brokerProperties, null);
+         }
+      }
+      parsePrefixedProperties(System.getProperties(), systemPropertyPrefix);
       return this;
    }
 
-   @Override
-   public Configuration parseSystemProperties(Properties properties) throws 
Exception {
+   public void parsePrefixedProperties(Properties properties, String prefix) 
throws Exception {
       Map<String, Object> beanProperties = new HashMap<>();
 
       synchronized (properties) {
+         String key = null;
          for (Map.Entry<Object, Object> entry : properties.entrySet()) {
-            if (entry.getKey().toString().startsWith(systemPropertyPrefix)) {
-               String key = 
entry.getKey().toString().substring(systemPropertyPrefix.length());
-               logger.debug("Setting up config, " + key + "=" + 
entry.getValue());
-               beanProperties.put(key, entry.getValue());
+            key = entry.getKey().toString();
+            if (prefix != null) {
+               if (!key.startsWith(prefix)) {
+                  continue;
+               }
+               key = entry.getKey().toString().substring(prefix.length());
             }
+            logger.debug("Setting up config, " + key + "=" + entry.getValue());
+            beanProperties.put(key, entry.getValue());
          }
       }
 
       if (!beanProperties.isEmpty()) {
-         BeanSupport.setData(this, beanProperties);
+         populateWithProperties(beanProperties);
       }
+   }
 
-      return this;
+   public void populateWithProperties(Map<String, Object> beanProperties) 
throws InvocationTargetException, IllegalAccessException {
+      BeanUtilsBean beanUtils = new BeanUtilsBean(new ConvertUtilsBean(), new 
CollectionAutoFillPropertiesUtil());
+      // nested property keys delimited by . and enclosed by '"' if they key's 
themselves contain dots
+      beanUtils.getPropertyUtils().setResolver(new 
SurroundResolver(getBrokerPropertiesKeySurround(beanProperties)));
+      beanUtils.getConvertUtils().register(new Converter() {
+         @Override
+         public <T> T convert(Class<T> type, Object value) {
+            return (T) SimpleString.toSimpleString(value.toString());
+         }
+      }, SimpleString.class);
+      beanUtils.getPropertyUtils().addBeanIntrospector(new 
FluentPropertyBeanIntrospectorWithIgnores());
+
+      beanUtils.populate(this, beanProperties);
+   }
+
+   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));
+      } else {
+         return System.getProperty(getSystemPropertyPrefix() + 
ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY, 
getBrokerPropertiesKeySurround());
+      }
    }
 
    @Override
@@ -698,6 +759,11 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
       return this;
    }
 
+   public ConfigurationImpl addConnectorConfiguration(final 
TransportConfiguration info) {
+      connectorConfigs.put(info.getName(), info);
+      return this;
+   }
+
    @Override
    public ConfigurationImpl addConnectorConfiguration(final String name, final 
String uri) throws Exception {
 
@@ -795,6 +861,10 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
       return this.amqpBrokerConnectConfigurations;
    }
 
+   public List<AMQPBrokerConnectConfiguration> getAMQPConnections() {
+      return this.amqpBrokerConnectConfigurations;
+   }
+
    @Override
    public ConfigurationImpl clearClusterConfigurations() {
       clusterConfigurations.clear();
@@ -1555,6 +1625,10 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
       return this;
    }
 
+   public ConfigurationImpl addResourceLimitSetting(ResourceLimitSettings 
resourceLimitSettings) {
+      return this.addResourceLimitSettings(resourceLimitSettings);
+   }
+
    @Override
    public Map<String, Set<Role>> getSecurityRoles() {
       for (SecuritySettingPlugin securitySettingPlugin : 
securitySettingPlugins) {
@@ -2603,4 +2677,190 @@ public class ConfigurationImpl implements 
Configuration, Serializable {
       return this;
    }
 
+   // extend property utils with ability to auto-fill and locate from 
collections
+   // collection entries are identified by the name() property
+   private static class CollectionAutoFillPropertiesUtil extends 
PropertyUtilsBean {
+
+      private static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{};
+      final Stack<Pair<String, Object>> collections = new Stack<>();
+
+      @Override
+      public void setProperty(final Object bean, final String name, final 
Object value) throws InvocationTargetException, IllegalAccessException, 
NoSuchMethodException {
+         // any set will invalidate our collections stack
+         if (!collections.isEmpty()) {
+            Pair<String, Object> collectionInfo = collections.pop();
+         }
+         super.setProperty(bean, name, value);
+      }
+
+      // need to track collections such that we can locate or create entries 
on demand
+      @Override
+      public Object getProperty(final Object bean,
+                                final String name) throws 
IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+
+         if (!collections.isEmpty()) {
+            final String key = getResolver().getProperty(name);
+            Pair<String, Object> collectionInfo = collections.pop();
+            if (bean instanceof Map) {
+               Map map = (Map) bean;
+               if (!map.containsKey(key)) {
+                  map.put(key, 
newNamedInstanceForCollection(collectionInfo.getA(), collectionInfo.getB(), 
key));
+               }
+               return map.get(key);
+            } else { // collection
+               // locate on name property
+               for (Object candidate : (Collection) bean) {
+                  if (key.equals(getProperty(candidate, "name"))) {
+                     return candidate;
+                  }
+               }
+               // or create it
+               Object created = 
newNamedInstanceForCollection(collectionInfo.getA(), collectionInfo.getB(), 
key);
+               ((Collection) bean).add(created);
+               return created;
+            }
+         }
+
+         Object resolved = getNestedProperty(bean, name);
+
+         if (resolved instanceof Collection || resolved instanceof Map) {
+            collections.push(new Pair<String, Object>(name, bean));
+         }
+         return resolved;
+      }
+
+      // allow finding beans in collections via name() such that a mapped key 
(key)
+      // can be used to access and *not* auto create entries
+      @Override
+      public Object getMappedProperty(final Object bean,
+                                      final String name, final String key)
+         throws IllegalAccessException, InvocationTargetException,
+         NoSuchMethodException {
+
+         if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+         }
+         if (name == null) {
+            throw new IllegalArgumentException("No name specified for bean 
class '" +
+                                                  bean.getClass() + "'");
+         }
+         if (key == null) {
+            throw new IllegalArgumentException("No key specified for property 
'" +
+                                                  name + "' on bean class " + 
bean.getClass() + "'");
+         }
+
+         Object result = null;
+
+         final PropertyDescriptor descriptor = getPropertyDescriptor(bean, 
name);
+         if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                                               name + "'+ on bean class '" + 
bean.getClass() + "'");
+         }
+
+         if (descriptor instanceof MappedPropertyDescriptor) {
+            // Call the keyed getter method if there is one
+            Method readMethod = ((MappedPropertyDescriptor) descriptor).
+               getMappedReadMethod();
+            readMethod = MethodUtils.getAccessibleMethod(bean.getClass(), 
readMethod);
+            if (readMethod != null) {
+               final Object[] keyArray = new Object[1];
+               keyArray[0] = key;
+               result = readMethod.invoke(bean, keyArray);
+            } else {
+               throw new NoSuchMethodException("Property '" + name +
+                                                  "' has no mapped getter 
method on bean class '" +
+                                                  bean.getClass() + "'");
+            }
+         } else {
+            final Method readMethod = 
MethodUtils.getAccessibleMethod(bean.getClass(), descriptor.getReadMethod());
+            if (readMethod != null) {
+               final Object invokeResult = readMethod.invoke(bean, 
EMPTY_OBJECT_ARRAY);
+               if (invokeResult instanceof Map) {
+                  result = ((Map<?, ?>)invokeResult).get(key);
+               } else if (invokeResult instanceof Collection) {
+                  // locate on name property
+                  for (Object candidate : (Collection) invokeResult) {
+                     if (key.equals(getProperty(candidate, "name"))) {
+                        return candidate;
+                     }
+                  }
+               }
+            } else {
+               throw new NoSuchMethodException("Property '" + name +
+                                                  "' has no mapped getter 
method on bean class '" +
+                                                  bean.getClass() + "'");
+            }
+         }
+         return result;
+      }
+
+      private Object newNamedInstanceForCollection(String 
collectionPropertyName, Object hostingBean, String name) {
+         // find the add X and init an instance of the type with name=name
+
+         // expect an add... without the plural
+         String addPropertyName = "add" + 
Character.toUpperCase(collectionPropertyName.charAt(0)) + 
collectionPropertyName.substring(1, collectionPropertyName.length() - 1);
+
+         // we don't know the type, infer from add method add(X x) or 
add(String key, X x)
+         final Method[] methods = hostingBean.getClass().getMethods();
+         for (Method candidate : methods) {
+            if (candidate.getName().equals(addPropertyName) &&
+               (candidate.getParameterCount() == 1 ||
+                  (candidate.getParameterCount() == 2
+                     // has a String key
+                     && String.class.equals(candidate.getParameterTypes()[0])
+                     // but not initialised from a String form (eg: uri)
+                     && 
!String.class.equals(candidate.getParameterTypes()[1])))) {
+
+               // create one and initialise with name
+               try {
+                  Object instance = 
candidate.getParameterTypes()[candidate.getParameterCount() - 
1].getDeclaredConstructor().newInstance(null);
+                  try {
+                     setProperty(instance, "name", name);
+                  } catch (NoSuchMethodException okIgnore) {
+                  }
+
+                  // this is always going to be a little hacky b/c our config 
is not natively property friendly
+                  if (instance instanceof TransportConfiguration) {
+                     setProperty(instance, "factoryClassName", 
"invm".equals(name) ? InVMConnectorFactory.class.getName() : 
NettyConnectorFactory.class.getName());
+                  }
+                  return instance;
+
+               } catch (Exception e) {
+                  logger.debug("Failed to add entry for " + name + " with 
method: " + candidate, e);
+                  throw new IllegalArgumentException("failed to add entry for 
collection key " + name, e);
+               }
+            }
+         }
+         throw new IllegalArgumentException("failed to locate add method for 
collection property " + addPropertyName);
+      }
+   }
+
+   private static class SurroundResolver extends DefaultResolver {
+      final String surroundString;
+
+      SurroundResolver(String surroundString) {
+         this.surroundString = surroundString;
+      }
+
+      @Override
+      public String next(String expression) {
+         String result = super.next(expression);
+         if (result != null) {
+            if (result.startsWith(surroundString)) {
+               // we need to recompute to properly terminate this SURROUND
+               result = 
expression.substring(expression.indexOf(surroundString));
+               return result.substring(0, result.indexOf(surroundString, 
surroundString.length()) + surroundString.length());
+            }
+         }
+         return result;
+      }
+
+      @Override
+      public String getProperty(final String expression) {
+         if (expression.startsWith(surroundString) && 
expression.endsWith(surroundString)) {
+            return expression.substring(surroundString.length(), 
expression.length() - surroundString.length());
+         }
+         return super.getProperty(expression);
+      }
+   }
 }
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
index 01ac199..1c253ef 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
@@ -57,8 +57,6 @@ public final class FileConfiguration extends 
ConfigurationImpl implements Deploy
 
       setConfigurationUrl(url);
 
-      parseSystemProperties();
-
       parsed = true;
    }
 
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
index 4d9b9cd..85049c1 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
@@ -2052,7 +2052,7 @@ public final class FileConfigurationParser extends 
XMLConfigurationUtil {
       String uri = e.getAttribute("uri");
 
       int retryInterval = getAttributeInteger(e, "retry-interval", 5000, 
Validators.GT_ZERO);
-      int reconnectAttemps = getAttributeInteger(e, "reconnect-attempts", -1, 
Validators.MINUS_ONE_OR_GT_ZERO);
+      int reconnectAttempts = getAttributeInteger(e, "reconnect-attempts", -1, 
Validators.MINUS_ONE_OR_GT_ZERO);
       String user = getAttributeValue(e, "user");
       String password = getAttributeValue(e, "password");
       boolean autoStart = getBooleanAttribute(e, "auto-start", true);
@@ -2061,7 +2061,7 @@ public final class FileConfigurationParser extends 
XMLConfigurationUtil {
 
       AMQPBrokerConnectConfiguration config = new 
AMQPBrokerConnectConfiguration(name, uri);
       config.parseURI();
-      
config.setRetryInterval(retryInterval).setReconnectAttempts(reconnectAttemps).setUser(user).setPassword(password).setAutostart(autoStart);
+      
config.setRetryInterval(retryInterval).setReconnectAttempts(reconnectAttempts).setUser(user).setPassword(password).setAutostart(autoStart);
 
       mainConfig.addAMQPConnection(config);
 
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
index 35d4f63..8bd978c 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
@@ -961,4 +961,7 @@ public interface ActiveMQServer extends ServiceComponent {
    BrokerBalancerManager getBalancerManager();
 
    String validateUser(String username, String password, RemotingConnection 
connection, String securityDomain) throws Exception;
+
+   default void setProperties(String fileUrltoBrokerProperties) {
+   }
 }
\ No newline at end of file
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
index fe0ed5e..6c12d36 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
@@ -17,8 +17,11 @@
 package org.apache.activemq.artemis.core.server.embedded;
 
 import javax.management.MBeanServer;
+import java.io.File;
+import java.net.URL;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
 import org.apache.activemq.artemis.core.config.Configuration;
 import org.apache.activemq.artemis.core.config.FileDeploymentManager;
 import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
@@ -140,6 +143,11 @@ public class EmbeddedActiveMQ {
       } else {
          activeMQServer = new ActiveMQServerImpl(configuration, mbeanServer, 
securityManager);
       }
+
+      URL brokerPropertiesFromClasspath = 
this.getClass().getClassLoader().getResource(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME);
+      if (brokerPropertiesFromClasspath != null) {
+         activeMQServer.setProperties(new 
File(brokerPropertiesFromClasspath.toURI()).getAbsolutePath());
+      }
    }
 
    public EmbeddedActiveMQ stop() throws Exception {
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
index be7a540..48d827f 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
@@ -369,6 +369,8 @@ public class ActiveMQServerImpl implements ActiveMQServer {
 
    private volatile FederationManager federationManager;
 
+   private String propertiesFileUrl;
+
    private final ActiveMQComponent networkCheckMonitor = new 
ActiveMQComponent() {
       @Override
       public void start() throws Exception {
@@ -593,13 +595,18 @@ public class ActiveMQServerImpl implements ActiveMQServer 
{
       return this.analyzer;
    }
 
+   @Override
+   public void setProperties(String fileUrltoBrokerProperties) {
+      propertiesFileUrl = fileUrltoBrokerProperties;
+   }
+
    private void internalStart() throws Exception {
       if (state != SERVER_STATE.STOPPED) {
          logger.debug("Server already started!");
          return;
       }
 
-      configuration.parseSystemProperties();
+      configuration.parseProperties(propertiesFileUrl);
 
       initializeExecutorServices();
 
@@ -4323,6 +4330,7 @@ public class ActiveMQServerImpl implements ActiveMQServer 
{
       configuration.setQueueConfigs(config.getQueueConfigs());
       configurationReloadDeployed.set(false);
       if (isActive()) {
+         configuration.parseProperties(propertiesFileUrl);
          deployReloadableConfigFromConfiguration();
       }
    }
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/ResourceLimitSettings.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/ResourceLimitSettings.java
index e8c0aae..c776e32 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/ResourceLimitSettings.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/ResourceLimitSettings.java
@@ -48,6 +48,10 @@ public class ResourceLimitSettings implements Serializable, 
EncodingSupport {
 
    //   SimpleString queueNameRegex = null;
 
+   public void setName(String name) {
+      setMatch(SimpleString.toSimpleString(name));
+   }
+
    public SimpleString getMatch() {
       return match != null ? match : DEFAULT_MATCH;
    }
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 146386d..317d6dd 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
@@ -24,7 +24,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.activemq.artemis.ArtemisConstants;
 import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
 import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.TransportConfiguration;
 import org.apache.activemq.artemis.core.config.Configuration;
+import 
org.apache.activemq.artemis.core.config.amqpBrokerConnectivity.AMQPBrokerConnectConfiguration;
+import 
org.apache.activemq.artemis.core.config.amqpBrokerConnectivity.AMQPBrokerConnectionAddressType;
+import 
org.apache.activemq.artemis.core.config.amqpBrokerConnectivity.AMQPMirrorBrokerConnectionElement;
 import org.apache.activemq.artemis.core.config.ha.LiveOnlyPolicyConfiguration;
 import org.apache.activemq.artemis.core.server.JournalType;
 import 
org.apache.activemq.artemis.core.server.plugin.impl.LoggingActiveMQServerPlugin;
@@ -584,12 +588,127 @@ public class ConfigurationImplTest extends 
ActiveMQTestBase {
       properties.put(configuration.getSystemPropertyPrefix() + 
"fileDeployerScanPeriod", "1234");
       properties.put(configuration.getSystemPropertyPrefix() + 
"globalMaxSize", "4321");
 
-      configuration.parseSystemProperties(properties);
+      configuration.parsePrefixedProperties(properties, 
configuration.getSystemPropertyPrefix());
 
       Assert.assertEquals(1234, configuration.getFileDeployerScanPeriod());
       Assert.assertEquals(4321, configuration.getGlobalMaxSize());
    }
 
+   @Test
+   public void testSetNestedPropertyOnCollections() throws Throwable {
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      Properties properties = new Properties();
+      properties.put("balancerConfigurations.joe.localTargetFilter", "LF");
+      properties.put("balancerConfigurations(joe).targetKeyFilter", "TF");
+
+      properties.put("acceptorConfigurations.tcp.params.HOST", "LOCALHOST");
+      properties.put("acceptorConfigurations.tcp.params.PORT", "61616");
+
+      properties.put("acceptorConfigurations.invm.params.ID", "0");
+
+      //   <amqp-connection uri="tcp://HOST:PORT" name="other-server" 
retry-interval="100" reconnect-attempts="-1" user="john" password="doe">
+      properties.put("AMQPConnections.other-server.uri", "tcp://HOST:PORT");
+      properties.put("AMQPConnections.other-server.retryInterval", "100");
+      properties.put("AMQPConnections.other-server.reconnectAttempts", "100");
+      properties.put("AMQPConnections.other-server.user", "john");
+      properties.put("AMQPConnections.other-server.password", "doe");
+
+      //   <amqp-connection uri="tcp://brokerB:5672" name="brokerB"> <mirror/> 
</amqp-connection>
+      properties.put("AMQPConnections.brokerB.uri", "tcp://brokerB:5672");
+      properties.put("AMQPConnections.brokerB.type", 
AMQPBrokerConnectionAddressType.MIRROR.toString());
+      
properties.put("AMQPConnections.brokerB.connectionElements.mirror.mirrorSNF", 
"mirrorSNFQueue");
+
+      properties.put("resourceLimitSettings.joe.maxConnections", "100");
+
+      configuration.parsePrefixedProperties(properties, null);
+
+      Assert.assertEquals(1, configuration.getBalancerConfigurations().size());
+      Assert.assertEquals("LF", 
configuration.getBalancerConfigurations().get(0).getLocalTargetFilter());
+      Assert.assertEquals("TF", 
configuration.getBalancerConfigurations().get(0).getTargetKeyFilter());
+
+      Assert.assertEquals(2, configuration.getAcceptorConfigurations().size());
+
+      for (TransportConfiguration acceptor : 
configuration.getAcceptorConfigurations()) {
+         if ("tcp".equals(acceptor.getName())) {
+            Assert.assertEquals("61616", acceptor.getParams().get("PORT"));
+         }
+         if ("invm".equals(acceptor.getName())) {
+            Assert.assertEquals("0", acceptor.getParams().get("ID"));
+         }
+      }
+
+      Assert.assertEquals(2, configuration.getAMQPConnection().size());
+      for (AMQPBrokerConnectConfiguration amqpBrokerConnectConfiguration : 
configuration.getAMQPConnection()) {
+         if ("brokerB".equals(amqpBrokerConnectConfiguration.getName())) {
+            
Assert.assertEquals(AMQPBrokerConnectionAddressType.MIRROR.toString(), 
amqpBrokerConnectConfiguration.getConnectionElements().get(0).getType().toString());
+            Assert.assertEquals("mirrorSNFQueue", 
((AMQPMirrorBrokerConnectionElement)amqpBrokerConnectConfiguration.getConnectionElements().get(0)).getMirrorSNF().toString());
+
+         } else if 
("other-server".equals(amqpBrokerConnectConfiguration.getName())) {
+            Assert.assertEquals(100, 
amqpBrokerConnectConfiguration.getReconnectAttempts());
+         } else {
+            fail("unexpected amqp broker connection configuration: " + 
amqpBrokerConnectConfiguration.getName());
+         }
+      }
+
+      Assert.assertEquals(100, 
configuration.getResourceLimitSettings().get("joe").getMaxConnections());
+   }
+
+   @Test
+   public void 
testSetNestedPropertyOnExistingCollectionEntryViaMappedNotation() throws 
Throwable {
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      Properties properties = new Properties();
+      properties.put("balancerConfigurations.joe.localTargetFilter", "LF");
+      // does not exist, ignored
+      properties.put("balancerConfigurations(bob).targetKeyFilter", "TF");
+      properties.put("balancerConfigurations(joe).targetKeyFilter", "TF");
+
+      configuration.parsePrefixedProperties(properties, null);
+
+      Assert.assertEquals(1, configuration.getBalancerConfigurations().size());
+      Assert.assertEquals("LF", 
configuration.getBalancerConfigurations().get(0).getLocalTargetFilter());
+      Assert.assertEquals("TF", 
configuration.getBalancerConfigurations().get(0).getTargetKeyFilter());
+   }
+
+   @Test
+   public void testAddressSettingsViaProperties() throws Throwable {
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      Properties properties = new Properties();
+
+      properties.put("addressesSettings.#.expiryAddress", "sharedExpiry");
+      properties.put("addressesSettings.NeedToTrackExpired.expiryAddress", 
"important");
+      properties.put("addressesSettings.\"Name.With.Dots\".expiryAddress", 
"moreImportant");
+
+      configuration.parsePrefixedProperties(properties, null);
+
+      Assert.assertEquals(3, configuration.getAddressesSettings().size());
+      Assert.assertEquals(SimpleString.toSimpleString("sharedExpiry"), 
configuration.getAddressesSettings().get("#").getExpiryAddress());
+      Assert.assertEquals(SimpleString.toSimpleString("important"), 
configuration.getAddressesSettings().get("NeedToTrackExpired").getExpiryAddress());
+      Assert.assertEquals(SimpleString.toSimpleString("moreImportant"), 
configuration.getAddressesSettings().get("Name.With.Dots").getExpiryAddress());
+   }
+
+   @Test
+   public void testNameWithDotsSurroundWithDollarDollar() throws Throwable {
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      Properties properties = new Properties();
+
+      // overrides the default surrounding string of '"' with '$$' using a 
property
+      
properties.put(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY,
 "$$");
+      properties.put("addressesSettings.#.expiryAddress", "sharedExpiry");
+      properties.put("addressesSettings.NeedToTrackExpired.expiryAddress", 
"important");
+      properties.put("addressesSettings.$$Name.With.Dots$$.expiryAddress", 
"moreImportant");
+
+      configuration.parsePrefixedProperties(properties, null);
+
+      Assert.assertEquals(3, configuration.getAddressesSettings().size());
+      Assert.assertEquals(SimpleString.toSimpleString("sharedExpiry"), 
configuration.getAddressesSettings().get("#").getExpiryAddress());
+      Assert.assertEquals(SimpleString.toSimpleString("important"), 
configuration.getAddressesSettings().get("NeedToTrackExpired").getExpiryAddress());
+      Assert.assertEquals(SimpleString.toSimpleString("moreImportant"), 
configuration.getAddressesSettings().get("Name.With.Dots").getExpiryAddress());
+   }
+
    /**
     * To test ARTEMIS-926
     * @throws Throwable
@@ -632,7 +751,7 @@ public class ConfigurationImplTest extends ActiveMQTestBase 
{
          properties.put(configuration.getSystemPropertyPrefix() + 
"fileDeployerScanPeriod", "1234");
          properties.put(configuration.getSystemPropertyPrefix() + 
"globalMaxSize", "4321");
 
-         configuration.parseSystemProperties(properties);
+         configuration.parsePrefixedProperties(properties, 
configuration.getSystemPropertyPrefix());
 
 
       } finally {
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/server/config/JMSServerPropertyConfigTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/server/config/JMSServerPropertyConfigTest.java
new file mode 100644
index 0000000..5e1c468
--- /dev/null
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/server/config/JMSServerPropertyConfigTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.activemq.artemis.tests.integration.jms.server.config;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
+import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
+import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
+import org.junit.Test;
+
+public class JMSServerPropertyConfigTest extends ActiveMQTestBase {
+
+   @Test
+   public void testConfigViaBrokerPropertiesSystemProperty() throws Exception {
+      EmbeddedActiveMQ server = new EmbeddedActiveMQ();
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      configuration.setJournalDirectory(new File(getTestDir(), 
"./journal").getAbsolutePath()).
+         setPagingDirectory(new File(getTestDir(), 
"./paging").getAbsolutePath()).
+         setLargeMessagesDirectory(new File(getTestDir(), 
"./largemessages").getAbsolutePath()).
+         setBindingsDirectory(new File(getTestDir(), 
"./bindings").getAbsolutePath()).setPersistenceEnabled(true);
+
+      File bindingsDir = new File(configuration.getBindingsDirectory());
+      bindingsDir.mkdirs();
+      File propertiesInBindingsDir = new File(bindingsDir, 
ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME);
+
+      try (PrintStream out = new PrintStream(new BufferedOutputStream(new 
FileOutputStream(propertiesInBindingsDir)))) {
+         // use the same name property as from the classpath broker.properties 
to verify precedence of system prop
+         out.println("name=nameFromCopiedPropertiesRefViaSystemProp");
+      }
+
+      
System.setProperty(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME,
 propertiesInBindingsDir.getAbsolutePath());
+      try {
+
+         server.setConfiguration(configuration);
+         server.start();
+
+         assertEquals("nameFromCopiedPropertiesRefViaSystemProp", 
server.getActiveMQServer().getConfiguration().getName());
+
+      } finally {
+         
System.getProperties().remove(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME);
+         server.stop();
+      }
+   }
+
+   @Test
+   public void testConfigViaBrokerPropertiesFromClasspath() throws Exception {
+
+      EmbeddedActiveMQ server = new EmbeddedActiveMQ();
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      configuration.setJournalDirectory(new File(getTestDir(), 
"./journal").getAbsolutePath()).
+         setPagingDirectory(new File(getTestDir(), 
"./paging").getAbsolutePath()).
+         setLargeMessagesDirectory(new File(getTestDir(), 
"./largemessages").getAbsolutePath()).
+         setBindingsDirectory(new File(getTestDir(), 
"./bindings").getAbsolutePath()).setPersistenceEnabled(true);
+
+      try {
+
+         server.setConfiguration(configuration);
+         server.start();
+
+         assertEquals("ConfiguredViaProperties", 
server.getActiveMQServer().getConfiguration().getName());
+
+      } finally {
+         server.stop();
+      }
+   }
+}
diff --git a/tests/integration-tests/src/test/resources/broker.properties 
b/tests/integration-tests/src/test/resources/broker.properties
new file mode 100644
index 0000000..d257e85
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/broker.properties
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+name=ConfiguredViaProperties
\ No newline at end of file

Reply via email to