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