ARTEMIS-601 load runtime security cfg file changes
This commit is contained in:
parent
85857ab8eb
commit
1ef9e74f14
|
@ -16,14 +16,31 @@
|
|||
*/
|
||||
package org.apache.activemq.cli.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
|
||||
import org.apache.activemq.artemis.dto.ServerDTO;
|
||||
import org.apache.activemq.artemis.integration.FileBroker;
|
||||
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class FileBrokerTest {
|
||||
|
||||
@Test
|
||||
|
@ -71,4 +88,63 @@ public class FileBrokerTest {
|
|||
broker.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigFileReload() throws Exception {
|
||||
ServerDTO serverDTO = new ServerDTO();
|
||||
serverDTO.configuration = "broker-reload.xml";
|
||||
FileBroker broker = null;
|
||||
String path = null;
|
||||
try {
|
||||
SecurityConfiguration securityConfiguration = new SecurityConfiguration();
|
||||
securityConfiguration.addUser("myUser", "myPass");
|
||||
securityConfiguration.addRole("myUser", "guest");
|
||||
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), securityConfiguration);
|
||||
broker = new FileBroker(serverDTO, securityManager);
|
||||
broker.start();
|
||||
ActiveMQServerImpl activeMQServer = (ActiveMQServerImpl) broker.getComponents().get("core");
|
||||
Assert.assertNotNull(activeMQServer);
|
||||
Assert.assertTrue(activeMQServer.isStarted());
|
||||
Assert.assertTrue(broker.isStarted());
|
||||
path = activeMQServer.getConfiguration().getConfigurationUrl().getPath();
|
||||
Assert.assertNotNull(activeMQServer.getConfiguration().getConfigurationUrl());
|
||||
|
||||
Thread.sleep(activeMQServer.getConfiguration().getConfigurationFileRefreshPeriod() * 2);
|
||||
|
||||
ServerLocator locator = ActiveMQClient.createServerLocator("tcp://localhost:61616");
|
||||
ClientSessionFactory sf = locator.createSessionFactory();
|
||||
ClientSession session = sf.createSession("myUser", "myPass", false, true, false, false, 0);
|
||||
ClientProducer producer = session.createProducer("jms.queue.DLQ");
|
||||
producer.send(session.createMessage(true));
|
||||
|
||||
replacePatternInFile(path, "guest", "X");
|
||||
|
||||
Thread.sleep(activeMQServer.getConfiguration().getConfigurationFileRefreshPeriod() * 2);
|
||||
|
||||
try {
|
||||
producer.send(session.createMessage(true));
|
||||
fail("Should throw a security exception");
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
|
||||
locator.close();
|
||||
}
|
||||
finally {
|
||||
assert broker != null;
|
||||
broker.stop();
|
||||
if (path != null) {
|
||||
replacePatternInFile(path, "X", "guest");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void replacePatternInFile(String file, String regex, String replacement) throws IOException {
|
||||
Path path = Paths.get(file);
|
||||
Charset charset = StandardCharsets.UTF_8;
|
||||
String content = new String(Files.readAllBytes(path), charset);
|
||||
String replaced = content.replaceAll(regex, replacement);
|
||||
Files.write(path, replaced.getBytes(charset));
|
||||
Files.setLastModifiedTime(path, FileTime.fromMillis(System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration xmlns="urn:activemq">
|
||||
<jms xmlns="urn:activemq:jms">
|
||||
<queue name="DLQ"/>
|
||||
<queue name="ExpiryQueue"/>
|
||||
</jms>
|
||||
<core xmlns="urn:activemq:core">
|
||||
<paging-directory>./target/paging</paging-directory>
|
||||
|
||||
<bindings-directory>./target/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./target/journal</journal-directory>
|
||||
|
||||
<journal-min-files>2</journal-min-files>
|
||||
|
||||
<large-messages-directory>./target/large-messages</large-messages-directory>
|
||||
|
||||
<configuration-file-refresh-period>500</configuration-file-refresh-period>
|
||||
|
||||
<connectors>
|
||||
<!-- Default Connector. Returned to clients during broadcast and distributed around cluster. See broadcast and discovery-groups -->
|
||||
<connector name="activemq">tcp://${activemq.remoting.default.host:localhost}:${activemq.remoting.default.port:61616}</connector>
|
||||
</connectors>
|
||||
|
||||
<acceptors>
|
||||
<!-- Default ActiveMQ Artemis Acceptor. Multi-protocol adapter. Currently supports Core, OpenWire, Stomp and AMQP. -->
|
||||
<acceptor name="activemq">tcp://${activemq.remoting.default.host:localhost}:${activemq.remoting.default.port:61616}</acceptor>
|
||||
|
||||
<!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic.-->
|
||||
<acceptor name="amqp">tcp://${activemq.remoting.amqp.host:localhost}:${activemq.remoting.amqp.port:5672}?protocols=AMQP</acceptor>
|
||||
|
||||
<!-- STOMP Acceptor. -->
|
||||
<acceptor name="stomp">tcp://${activemq.remoting.stomp.host:localhost}:${activemq.remoting.stomp.port:61613}?protocols=STOMP</acceptor>
|
||||
|
||||
<!-- HornetQ Compatibility Acceptor. Enables ActiveMQ Artemis Core and STOMP for legacy HornetQ clients. -->
|
||||
<acceptor name="hornetq">tcp://${activemq.remoting.hornetq.host:localhost}:${activemq.remoting.hornetq.port:5445}?protocols=CORE,STOMP</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<security-settings>
|
||||
<security-setting match="#">
|
||||
<permission type="send" roles="guest"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<address-settings>
|
||||
<!--default for catch all-->
|
||||
<address-setting match="#">
|
||||
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
|
||||
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
|
||||
<redelivery-delay>0</redelivery-delay>
|
||||
<max-size-bytes>10485760</max-size-bytes>
|
||||
<message-counter-history-day-limit>10</message-counter-history-day-limit>
|
||||
<address-full-policy>BLOCK</address-full-policy>
|
||||
</address-setting>
|
||||
</address-settings>
|
||||
</core>
|
||||
</configuration>
|
|
@ -426,6 +426,9 @@ public final class ActiveMQDefaultConfiguration {
|
|||
// Default period to wait between connection TTL checks
|
||||
public static final long DEFAULT_CONNECTION_TTL_CHECK_INTERVAL = 2000;
|
||||
|
||||
// Default period to wait between configuration file checks
|
||||
public static final long DEFAULT_CONFIGURATION_FILE_REFRESH_PERIOD = 5000;
|
||||
|
||||
/**
|
||||
* If true then the ActiveMQ Artemis Server will make use of any Protocol Managers that are in available on the classpath. If false then only the core protocol will be available, unless in Embedded mode where users can inject their own Protocol Managers.
|
||||
*/
|
||||
|
@ -1137,4 +1140,8 @@ public final class ActiveMQDefaultConfiguration {
|
|||
public static long getDefaultConnectionTtlCheckInterval() {
|
||||
return DEFAULT_CONNECTION_TTL_CHECK_INTERVAL;
|
||||
}
|
||||
|
||||
public static long getDefaultConfigurationFileRefreshPeriod() {
|
||||
return DEFAULT_CONFIGURATION_FILE_REFRESH_PERIOD;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.w3c.dom.Node;
|
|||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -57,7 +58,7 @@ public class FileJMSConfiguration extends JMSConfigurationImpl implements Deploy
|
|||
private boolean parsed = false;
|
||||
|
||||
@Override
|
||||
public void parse(Element config) throws Exception {
|
||||
public void parse(Element config, URL url) throws Exception {
|
||||
parseConfiguration(config);
|
||||
parsed = true;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.activemq.artemis.core.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -959,4 +960,12 @@ public interface Configuration {
|
|||
|
||||
long getConnectionTtlCheckInterval();
|
||||
|
||||
URL getConfigurationUrl();
|
||||
|
||||
Configuration setConfigurationUrl(URL configurationUrl);
|
||||
|
||||
long getConfigurationFileRefreshPeriod();
|
||||
|
||||
Configuration setConfigurationFileRefreshPeriod(long configurationFileRefreshPeriod);
|
||||
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public class FileDeploymentManager {
|
|||
if (root != null && children.getLength() > 0) {
|
||||
Node item = children.item(0);
|
||||
XMLUtil.validate(item, deployable.getSchema());
|
||||
deployable.parse((Element) item);
|
||||
deployable.parse((Element) item, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.io.Serializable;
|
|||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Array;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
|
@ -241,6 +242,10 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
|
||||
private long connectionTtlCheckInterval = ActiveMQDefaultConfiguration.getDefaultConnectionTtlCheckInterval();
|
||||
|
||||
private URL configurationUrl;
|
||||
|
||||
private long configurationFileRefreshPeriod = ActiveMQDefaultConfiguration.getDefaultConfigurationFileRefreshPeriod();
|
||||
|
||||
/**
|
||||
* Parent folder for all data folders.
|
||||
*/
|
||||
|
@ -1759,6 +1764,28 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getConfigurationUrl() {
|
||||
return configurationUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationImpl setConfigurationUrl(URL configurationUrl) {
|
||||
this.configurationUrl = configurationUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getConfigurationFileRefreshPeriod() {
|
||||
return configurationFileRefreshPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationImpl setConfigurationFileRefreshPeriod(long configurationFileRefreshPeriod) {
|
||||
this.configurationFileRefreshPeriod = configurationFileRefreshPeriod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* It will find the right location of a subFolder, related to artemisInstance
|
||||
*/
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.config.impl;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.activemq.artemis.core.deployers.Deployable;
|
||||
|
@ -44,7 +45,7 @@ public final class FileConfiguration extends ConfigurationImpl implements Deploy
|
|||
private boolean parsed = false;
|
||||
|
||||
@Override
|
||||
public void parse(Element config) throws Exception {
|
||||
public void parse(Element config, URL url) throws Exception {
|
||||
FileConfigurationParser parser = new FileConfigurationParser();
|
||||
|
||||
// https://jira.jboss.org/browse/HORNETQ-478 - We only want to validate AIO when
|
||||
|
@ -54,6 +55,8 @@ public final class FileConfiguration extends ConfigurationImpl implements Deploy
|
|||
|
||||
parser.parseMainConfig(config, this);
|
||||
|
||||
setConfigurationUrl(url);
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
|||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +33,7 @@ public interface Deployable {
|
|||
/*
|
||||
* parse the element from the xml configuration
|
||||
*/
|
||||
void parse(Element config) throws Exception;
|
||||
void parse(Element config, URL url) throws Exception;
|
||||
|
||||
/*
|
||||
* has this Deployable been parsed
|
||||
|
|
|
@ -280,6 +280,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
|||
|
||||
config.setConnectionTtlCheckInterval(getLong(e, "connection-ttl-check-interval", config.getConnectionTtlCheckInterval(), Validators.GT_ZERO));
|
||||
|
||||
config.setConfigurationFileRefreshPeriod(getLong(e, "configuration-file-refresh-period", config.getConfigurationFileRefreshPeriod(), Validators.GT_ZERO));
|
||||
|
||||
// parsing cluster password
|
||||
String passwordText = getString(e, "cluster-password", null, Validators.NO_CHECK);
|
||||
|
||||
|
|
|
@ -1498,4 +1498,8 @@ public interface ActiveMQServerLogger extends BasicLogger {
|
|||
@LogMessage(level = Logger.Level.ERROR)
|
||||
@Message(id = 224068, value = "Unable to stop component: {0}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void errorStoppingComponent(@Cause Throwable t, String componentClassName);
|
||||
|
||||
@LogMessage(level = Logger.Level.ERROR)
|
||||
@Message(id = 224069, value = "Change detected in broker configuration file, but reload failed", format = Message.Format.MESSAGE_FORMAT)
|
||||
void configurationReloadFailed(@Cause Throwable t);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.io.IOException;
|
|||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
|
@ -55,6 +56,7 @@ import org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
|
|||
import org.apache.activemq.artemis.core.config.DivertConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.StoreConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
|
||||
import org.apache.activemq.artemis.core.deployers.impl.FileConfigurationParser;
|
||||
import org.apache.activemq.artemis.core.filter.Filter;
|
||||
import org.apache.activemq.artemis.core.filter.impl.FilterImpl;
|
||||
import org.apache.activemq.artemis.core.io.IOCriticalErrorListener;
|
||||
|
@ -450,6 +452,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
|||
// start connector service
|
||||
connectorsService = new ConnectorsService(configuration, storageManager, scheduledPool, postOffice, serviceRegistry);
|
||||
connectorsService.start();
|
||||
|
||||
if (configuration.getConfigurationUrl() != null && getScheduledPool() != null) {
|
||||
getScheduledPool().scheduleWithFixedDelay(new ConfigurationFileReloader(this), configuration.getConfigurationFileRefreshPeriod(), configuration.getConfigurationFileRefreshPeriod(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// this avoids embedded applications using dirty contexts from startup
|
||||
|
@ -2351,4 +2357,38 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
private final class ConfigurationFileReloader extends Thread {
|
||||
long lastModified;
|
||||
boolean first = true;
|
||||
ActiveMQServer server;
|
||||
|
||||
ConfigurationFileReloader(ActiveMQServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
URL url = server.getConfiguration().getConfigurationUrl();
|
||||
long currentLastModified = new File(url.toURI()).lastModified();
|
||||
if (first) {
|
||||
first = false;
|
||||
lastModified = currentLastModified;
|
||||
return;
|
||||
}
|
||||
if (currentLastModified > lastModified) {
|
||||
if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) {
|
||||
ActiveMQServerLogger.LOGGER.debug("Configuration file change detected. Reloading...");
|
||||
}
|
||||
Configuration config = new FileConfigurationParser().parseMainConfig(url.openStream());
|
||||
securityRepository.swap(config.getSecurityRoles().entrySet());
|
||||
|
||||
lastModified = currentLastModified;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
ActiveMQServerLogger.LOGGER.configurationReloadFailed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.activemq.artemis.core.settings;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* allows objects to be mapped against a regex pattern and held in order in a list
|
||||
|
@ -85,6 +87,8 @@ public interface HierarchicalRepository<T> {
|
|||
*/
|
||||
void clear();
|
||||
|
||||
void swap(Set<Map.Entry<String, T>> entries);
|
||||
|
||||
/**
|
||||
* Removes all listeners.
|
||||
*/
|
||||
|
|
|
@ -147,6 +147,10 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
*/
|
||||
@Override
|
||||
public void addMatch(final String match, final T value, final boolean immutableMatch) {
|
||||
addMatch(match, value, immutableMatch, true);
|
||||
}
|
||||
|
||||
private void addMatch(final String match, final T value, final boolean immutableMatch, boolean notifyListeners) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
clearCache();
|
||||
|
@ -164,7 +168,9 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
}
|
||||
|
||||
// Calling the onChange outside of the wrieLock as some listeners may be doing reads on the matches
|
||||
onChange();
|
||||
if (notifyListeners) {
|
||||
onChange();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,6 +323,24 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(Set<Map.Entry<String, T>> entries) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
clearCache();
|
||||
immutables.clear();
|
||||
matches.clear();
|
||||
for (Map.Entry<String, T> entry : entries) {
|
||||
addMatch(entry.getKey(), entry.getValue(), true, false);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
onChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearListeners() {
|
||||
listeners.clear();
|
||||
|
|
|
@ -246,6 +246,14 @@
|
|||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="configuration-file-refresh-period" type="xsd:long" default="5000" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
how often (in ms) to check the configuration file for modifications
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="async-connection-execution-enabled" type="xsd:boolean" default="true" maxOccurs="1"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
|
|
|
@ -104,6 +104,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
|
|||
Assert.assertEquals(12345, conf.getGracefulShutdownTimeout());
|
||||
Assert.assertEquals(true, conf.isPopulateValidatedUser());
|
||||
Assert.assertEquals(98765, conf.getConnectionTtlCheckInterval());
|
||||
Assert.assertEquals(1234567, conf.getConfigurationFileRefreshPeriod());
|
||||
|
||||
Assert.assertEquals("largemessagesdir", conf.getLargeMessagesDirectory());
|
||||
Assert.assertEquals(95, conf.getMemoryWarningThreshold());
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<persist-id-cache>true</persist-id-cache>
|
||||
<populate-validated-user>true</populate-validated-user>
|
||||
<connection-ttl-check-interval>98765</connection-ttl-check-interval>
|
||||
<configuration-file-refresh-period>1234567</configuration-file-refresh-period>
|
||||
<remoting-incoming-interceptors>
|
||||
<class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor1</class-name>
|
||||
<class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor2</class-name>
|
||||
|
|
Loading…
Reference in New Issue