Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1545,4 +1545,5 @@ default boolean isUsingDatabasePersistence() {
}

Map<String, JaasAppConfiguration> getJaasConfigs();
Configuration setJaasConfigs(Map<String, JaasAppConfiguration> configs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,25 @@ public static void validateConfiguration(Configuration configuration) {
compareTTLWithCheckPeriod(configuration);
}

public static void throwIfReloadableConfigProvidedWithoutFileAndBrokerPropertiesUrlNonNullAndReload(Configuration configuration, String propertiesFileUrl) {
if (configuration.getConfigurationUrl() == null && configuration.getConfigurationFileRefreshPeriod() > 0 && configuration.resolvePropertiesSources(propertiesFileUrl) != null) {
// if any non xml (programmatic) provided config is reloadable, on the first properties source reload it will whack that config as the reload has the source of truth for reloadable attributes
if (!configuration.getSecurityRoles().isEmpty() ||
!configuration.getAddressSettings().isEmpty() ||
!configuration.getDivertConfigurations().isEmpty() ||
!configuration.getAddressConfigurations().isEmpty() ||
!configuration.getQueueConfigs().isEmpty() ||
!configuration.getBridgeConfigurations().isEmpty() ||
!configuration.getConnectorConfigurations().isEmpty() ||
!configuration.getAcceptorConfigurations().isEmpty() ||
!configuration.getAMQPConnection().isEmpty() ||
!configuration.getConnectionRouters().isEmpty()) {
Comment on lines +155 to +164
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not the whole method, then at least this bit of it seems like it should maybe be in the Configuration so its less likely to go stale from not being updated when the Configuration is.

E.g this is actually incorrect here already, because it does not match what you do later in the config reload bits below (which points to some missing testing).


throw new IllegalArgumentException(String.format("a properties source (%s) is illegal, programmatic config contains reloadable elements and configurationFileRefreshPeriod > 0; your programmatic config will be replaced on reload of the properties source", propertiesFileUrl));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like IllegalState might be more appropriate since this is used in the setProperties(..) method and the very same properties path argument could be valid depending on the existing config/state.

}
}
}

public static List<TransportConfiguration> parseAcceptorURI(String name, String uri) {
try {
// remove all whitespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,15 @@ public void addJaasConfig(JaasAppConfiguration config) {
jaasConfigs.put(config.getName(), config);
}

@Override
public Configuration setJaasConfigs(Map<String, JaasAppConfiguration> configs) {
jaasConfigs.putAll(configs);
// prune removed entries after update to retain existing entries, this is live config referenced by jaas
// see org.apache.activemq.artemis.core.config.impl.ConfigurationImpl.getAppConfigurationEntry
jaasConfigs.keySet().retainAll(configs.keySet());
return this;
}

private void writeProperties(FileWriter writer) throws Exception {
final BeanUtilsBean beanUtilsBean = new BeanUtilsBean();
beanUtilsBean.getPropertyUtils().addBeanIntrospector(new FluentPropertyBeanIntrospectorWithIgnores());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
import org.slf4j.LoggerFactory;

import static java.util.stream.Collectors.groupingBy;
import static org.apache.activemq.artemis.core.config.ConfigurationUtils.throwIfReloadableConfigProvidedWithoutFileAndBrokerPropertiesUrlNonNullAndReload;
import static org.apache.activemq.artemis.utils.collections.IterableStream.iterableOf;

/**
Expand Down Expand Up @@ -681,6 +682,7 @@ public CriticalAnalyzer getCriticalAnalyzer() {
@Override
public void setProperties(String fileUrltoBrokerProperties) {
propertiesFileUrl = fileUrltoBrokerProperties;
throwIfReloadableConfigProvidedWithoutFileAndBrokerPropertiesUrlNonNullAndReload(configuration, propertiesFileUrl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check should be before the path is set, otherwise it is ineffective and acts as if this is a perfectly valid argument (as the later test shows).

The exception should be documented.

}

@Override
Expand Down Expand Up @@ -4682,22 +4684,28 @@ public void reloadConfigurationFile() throws Exception {
}

private void reloadConfigurationFile(URL xmlConfigUri) throws Exception {
Configuration config = new ConfigurationImpl();
if (xmlConfigUri != null) {
Configuration config = new FileConfigurationParser().parseMainConfig(xmlConfigUri.openStream());
config = new FileConfigurationParser().parseMainConfig(xmlConfigUri.openStream());
LegacyJMSConfiguration legacyJMSConfiguration = new LegacyJMSConfiguration(config);
legacyJMSConfiguration.parseConfiguration(xmlConfigUri.openStream());
configuration.setSecurityRoles(config.getSecurityRoles());
configuration.setAddressSettings(config.getAddressSettings());
configuration.setDivertConfigurations(config.getDivertConfigurations());
configuration.setAddressConfigurations(config.getAddressConfigurations());
configuration.setQueueConfigs(config.getQueueConfigs());
configuration.setBridgeConfigurations(config.getBridgeConfigurations());
configuration.setConnectorConfigurations(config.getConnectorConfigurations());
configuration.setAcceptorConfigurations(config.getAcceptorConfigurations());
configuration.setAMQPConnectionConfigurations(config.getAMQPConnection());
configuration.setPurgePageFolders(config.isPurgePageFolders());
}
configuration.parseProperties(propertiesFileUrl);
config.parseProperties(propertiesFileUrl);
configuration.setStatus(config.getStatus());

configuration.setSecurityRoles(config.getSecurityRoles());
configuration.setAddressSettings(config.getAddressSettings());
configuration.setDivertConfigurations(config.getDivertConfigurations());
configuration.setAddressConfigurations(config.getAddressConfigurations());
configuration.setQueueConfigs(config.getQueueConfigs());
configuration.setBridgeConfigurations(config.getBridgeConfigurations());
configuration.setConnectorConfigurations(config.getConnectorConfigurations());
configuration.setAcceptorConfigurations(config.getAcceptorConfigurations());
configuration.setAMQPConnectionConfigurations(config.getAMQPConnection());
configuration.setPurgePageFolders(config.isPurgePageFolders());
configuration.setConnectionRouters(config.getConnectionRouters()); // needs reload logic
configuration.setJaasConfigs(config.getJaasConfigs());
Comment on lines +4706 to +4707
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doenst properly align with the checks done previously (see earlier comment).

It also adds [XML] reload (though without logic?) for bits that were not covered before, which doesnt seem suited to the Jira description and feels somewhat separate.


updateStatus(ServerStatus.CONFIGURATION_COMPONENT, configuration.getStatus());
configurationReloadDeployed.set(false);
if (isActive()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ private void prepareNodesAndStartCombinedHeadTail() throws Exception {
.setAutoDeleteQueues(false).setAutoDeleteAddresses(false); // so slow consumer can kick in!

Configuration baseConfig = new ConfigurationImpl();
baseConfig.setConfigurationFileRefreshPeriod(-1); // the classpath has broker.properties we don't want to reload
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it probably shouldnt since that would mean we dont actually know the current config of the broker during most of the tests.

baseConfig.getAddressSettings().put(qName, blockingQueue);

ConnectionRouterConfiguration connectionRouterConfiguration = new ConnectionRouterConfiguration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@
*/
package org.apache.activemq.artemis.tests.integration.server;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.FileOutputStream;
import java.io.StringReader;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
Expand All @@ -36,13 +33,21 @@
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
import org.apache.activemq.artemis.jms.server.config.impl.FileJMSConfiguration;
import org.apache.activemq.artemis.json.JsonObject;
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.apache.activemq.artemis.utils.JsonLoader;
import org.apache.activemq.artemis.utils.RandomUtil;
import org.apache.activemq.artemis.tests.util.Wait;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ConfigurationTest extends ActiveMQTestBase {

@Test
Expand Down Expand Up @@ -183,11 +188,15 @@ public void testPropertiesOnlyConfigReload() throws Exception {
properties.put("configurationFileRefreshPeriod", "100");
properties.put("persistenceEnabled", "false");
properties.put("connectionRouters.joe.localTargetFilter", "LF");
properties.put("acceptorConfigurations.tcp.factoryClassName", NETTY_ACCEPTOR_FACTORY);
properties.put("acceptorConfigurations.tcp.params.HOST", "LOCALHOST");
properties.put("acceptorConfigurations.tcp.params.PORT", "61616");

try (FileOutputStream outStream = new FileOutputStream(propsFile)) {
properties.store(outStream, null);
}
assertTrue(propsFile.exists());
properties.clear();

FileConfiguration fc = new FileConfiguration();
ActiveMQJAASSecurityManager sm = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), new SecurityConfiguration());
Expand All @@ -199,12 +208,13 @@ public void testPropertiesOnlyConfigReload() throws Exception {

assertEquals(1, server.getConfiguration().getConnectionRouters().size());
assertEquals("LF", server.getConfiguration().getConnectionRouters().get(0).getLocalTargetFilter());

properties.put("persistenceEnabled", "false");
properties.put("configurationFileRefreshPeriod", "100");

assertEquals(1, server.getActiveMQServerControl().getAcceptors().length);
// verify update
properties.put("configurationFileRefreshPeriod", "100");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like either some comment needed to explain better, or the properties clear should be here, or better a fresh set of properties used.

Could probably do with a comment either way to describe the changes such this is both 'update' and the later 'remove' changes.

properties.put("persistenceEnabled", "false");
properties.put("connectionRouters.joe.localTargetFilter", "UPDATED");

String startedStatus = server.getStatus();
try (FileOutputStream outStream = new FileOutputStream(propsFile)) {
properties.store(outStream, null);
}
Expand All @@ -213,6 +223,20 @@ public void testPropertiesOnlyConfigReload() throws Exception {
return "UPDATED".equals(server.getConfiguration().getConnectionRouters().get(0).getLocalTargetFilter());
});

// verify remove
assertEquals(0, server.getActiveMQServerControl().getAcceptors().length);

// verify status json reflects update
String updatedStatus = server.getStatus();
assertNotEquals(startedStatus, updatedStatus);
assertTrue(startedStatus.contains(propsFile.getName()));
assertTrue(updatedStatus.contains(propsFile.getName()));
JsonObject jsonStarted = JsonLoader.readObject(new StringReader(startedStatus));
JsonObject jsonUpdated = JsonLoader.readObject(new StringReader(updatedStatus));
String alder32Used = jsonStarted.getJsonObject("configuration").getJsonObject("properties").getJsonObject(propsFile.getName()).getString("fileAlder32");
String alder32Updated = jsonUpdated.getJsonObject("configuration").getJsonObject("properties").getJsonObject(propsFile.getName()).getString("fileAlder32");
assertNotEquals(alder32Used, alder32Updated);

} finally {
try {
server.stop();
Expand Down Expand Up @@ -350,6 +374,55 @@ public void testPropertiesDirWithFilterConfigReloadOnNewFileAfterGettingJournalL
}
}

@Test
public void testPropertiesAndProgrammaticReloadableConfigArg() throws Exception {

File propsFile = new File(getTestDirfile(), "somemore.props");
propsFile.createNewFile();


Properties properties = new ConfigurationImpl.InsertionOrderedProperties();
properties.put("configurationFileRefreshPeriod", "100");
properties.put("persistenceEnabled", "false");
properties.put("acceptorConfigurations.reloadable.factoryClassName", NETTY_ACCEPTOR_FACTORY);
properties.put("acceptorConfigurations.reloadable.params.HOST", "LOCALHOST");
properties.put("acceptorConfigurations.reloadable.params.PORT", "61616");

try (FileOutputStream outStream = new FileOutputStream(propsFile)) {
properties.store(outStream, null);
}
assertTrue(propsFile.exists());

ConfigurationImpl programmatic = new ConfigurationImpl();
programmatic.addAcceptorConfiguration("tcp", "tcp://localhost:62618");
ActiveMQJAASSecurityManager sm = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), new SecurityConfiguration());
ActiveMQServer server = addServer(new ActiveMQServerImpl(programmatic, sm));

assertThrows(IllegalArgumentException.class, () -> {
server.setProperties(propsFile.getAbsolutePath());
});
Comment on lines +401 to +403
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesnt really make sense. You explicily check it throws IAE (again ISE seems more in line), but then the test proceeds and acts as if this was a perfectly valid argument and the IAE didnt happen, and explicitly checks the 'new properties get reloaded and tosses away all original configuration' thing that didnt used to happen.

try {

server.start();

assertEquals(2, server.getActiveMQServerControl().getAcceptors().length);

// no change, just a touch
try (FileOutputStream outStream = new FileOutputStream(propsFile)) {
properties.store(outStream, null);
}

// reloaded properties are the source of truth
Wait.assertEquals(1, ()-> server.getActiveMQServerControl().getAcceptors().length);

} finally {
try {
server.stop();
} catch (Exception e) {
}
}
}

protected ActiveMQServer getActiveMQServer(String brokerConfig) throws Exception {
FileConfiguration fc = new FileConfiguration();
FileJMSConfiguration fileConfiguration = new FileJMSConfiguration();
Expand Down