ARTEMIS-1575 configure custom broker plugins with key/value properties.

The properties are read and passed into the the broker plugin's init(Map<String,String>)
This commit is contained in:
Pat Fox 2017-12-23 21:04:31 +01:00 committed by Justin Bertram
parent 1ef8199f23
commit d95757057e
10 changed files with 168 additions and 50 deletions

View File

@ -703,6 +703,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
private ActiveMQServerPlugin parseActiveMQServerPlugin(Node item) { private ActiveMQServerPlugin parseActiveMQServerPlugin(Node item) {
final String clazz = item.getAttributes().getNamedItem("class-name").getNodeValue(); final String clazz = item.getAttributes().getNamedItem("class-name").getNodeValue();
Map<String, String> properties = getMapOfChildPropertyElements(item);
ActiveMQServerPlugin serverPlugin = AccessController.doPrivileged(new PrivilegedAction<ActiveMQServerPlugin>() { ActiveMQServerPlugin serverPlugin = AccessController.doPrivileged(new PrivilegedAction<ActiveMQServerPlugin>() {
@Override @Override
public ActiveMQServerPlugin run() { public ActiveMQServerPlugin run() {
@ -710,9 +712,25 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
} }
}); });
serverPlugin.init(properties);
return serverPlugin; return serverPlugin;
} }
private Map<String, String> getMapOfChildPropertyElements(Node item) {
Map<String, String> properties = new HashMap<>();
NodeList children = item.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeName().equals("property")) {
String key = getAttributeValue(child, "key");
String value = getAttributeValue(child, "value");
properties.put(key, value);
}
}
return properties;
}
/** /**
* @param e * @param e
* @param config * @param config
@ -1656,16 +1674,7 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
Element element = (Element) node; Element element = (Element) node;
String className = getString(element, "class-name", null, Validators.NO_CHECK); String className = getString(element, "class-name", null, Validators.NO_CHECK);
Map<String, String> properties = new HashMap<>(); Map<String, String> properties = getMapOfChildPropertyElements(element);
NodeList children = element.getChildNodes();
for (int j = 0; j < children.getLength(); j++) {
Node child = children.item(j);
if (child.getNodeName().equals("property")) {
String key = getAttributeValue(child, "key");
String value = getAttributeValue(child, "value");
properties.put(key, value);
}
}
return new TransformerConfiguration(className).setProperties(properties); return new TransformerConfiguration(className).setProperties(properties);
} }

View File

@ -460,4 +460,11 @@ public interface ActiveMQServerPlugin {
default void criticalFailure(CriticalComponent components) throws ActiveMQException { default void criticalFailure(CriticalComponent components) throws ActiveMQException {
} }
/**
* used to pass configured properties to Plugin
*
* @param properties
*/
default void init(Map<String, String> properties) {
}
} }

View File

@ -934,6 +934,15 @@
a broker plugin a broker plugin
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
<xsd:sequence>
<xsd:element ref="property" maxOccurs="unbounded" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
properties to configure a plugin
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="class-name" type="xsd:string" use="required"> <xsd:attribute name="class-name" type="xsd:string" use="required">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
@ -1443,7 +1452,7 @@
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:element> </xsd:element>
<xsd:element name="property" type="transformerProperty" maxOccurs="unbounded" minOccurs="0"> <xsd:element ref="property" maxOccurs="unbounded" minOccurs="0">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
properties to configure the transformer class properties to configure the transformer class
@ -1453,23 +1462,24 @@
</xsd:sequence> </xsd:sequence>
</xsd:complexType> </xsd:complexType>
<xsd:element name="property">
<xsd:complexType name="transformerProperty"> <xsd:complexType>
<xsd:attribute name="key" type="xsd:string" use="required"> <xsd:attribute name="key" type="xsd:string" use="required">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
key for the property key for the property
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
<xsd:attribute name="value" type="xsd:string" use="required"> <xsd:attribute name="value" type="xsd:string" use="required">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
value for the property value for the property
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
</xsd:complexType> </xsd:complexType>
</xsd:element>
<!-- CLUSTER CONNECTION CONFIGURATION --> <!-- CLUSTER CONNECTION CONFIGURATION -->

View File

@ -20,7 +20,11 @@
xsi:schemaLocation="urn:activemq ../../../../activemq-server/src/main/resources/schema/artemis-server.xsd"> xsi:schemaLocation="urn:activemq ../../../../activemq-server/src/main/resources/schema/artemis-server.xsd">
<core xmlns="urn:activemq:core"> <core xmlns="urn:activemq:core">
<broker-plugins> <broker-plugins>
<broker-plugin class-name="org.apache.activemq.artemis.core.config.impl.FileConfigurationTest$EmptyPlugin1" /> <broker-plugin class-name="org.apache.activemq.artemis.core.config.impl.FileConfigurationTest$EmptyPlugin1">
<property key="key1" value="value1"/>
<property key="key2" value="value2"/>
<property key="key3" value="value3"/>
</broker-plugin>
<broker-plugin class-name="org.apache.activemq.artemis.core.config.impl.FileConfigurationTest$EmptyPlugin2" /> <broker-plugin class-name="org.apache.activemq.artemis.core.config.impl.FileConfigurationTest$EmptyPlugin2" />
</broker-plugins> </broker-plugins>
</core> </core>

View File

@ -1271,7 +1271,7 @@
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:element> </xsd:element>
<xsd:element name="property" type="transformerProperty" maxOccurs="unbounded" minOccurs="0"> <xsd:element ref="property" maxOccurs="unbounded" minOccurs="0">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
properties to configure the transformer class properties to configure the transformer class
@ -1281,23 +1281,24 @@
</xsd:sequence> </xsd:sequence>
</xsd:complexType> </xsd:complexType>
<xsd:element name="property">
<xsd:complexType name="transformerProperty"> <xsd:complexType>
<xsd:attribute name="key" type="xsd:string" use="required"> <xsd:attribute name="key" type="xsd:string" use="required">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
key for the property key for the property
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
<xsd:attribute name="value" type="xsd:string" use="required"> <xsd:attribute name="value" type="xsd:string" use="required">
<xsd:annotation> <xsd:annotation>
<xsd:documentation> <xsd:documentation>
value for the property value for the property
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
</xsd:complexType> </xsd:complexType>
</xsd:element>
<!-- CLUSTER CONNECTION CONFIGURATION --> <!-- CLUSTER CONNECTION CONFIGURATION -->

View File

@ -16,14 +16,20 @@ If you are using an embed system than you will need the jar under the regular cl
## Registering a Plugin ## Registering a Plugin
To register a plugin with by XML you need to add the `broker-plugins` element at the `broker.xml`. To register a plugin with by XML you need to add the `broker-plugins` element at the `broker.xml`. It is also possible
to pass configuration to a plugin using the `property` child element(s). These properties (zero to many)
will be read and passed into the Plugin's `init(Map<String, String>)` operation after the plugin
has been instantiated.
```xml ```xml
<configuration ...> <configuration ...>
... ...
<broker-plugins> <broker-plugins>
<broker-plugin class-name="some.plugin.UserPlugin" /> <broker-plugin class-name="some.plugin.UserPlugin">
<property key="property1" value="val_1" />
<property key="property2" value="val_2" />
</broker-plugin>
</broker-plugins> </broker-plugins>
... ...

View File

@ -0,0 +1,64 @@
/*
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.plugin;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.core.postoffice.RoutingStatus;
import org.apache.activemq.artemis.core.server.ServerSession;
import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerPlugin;
import org.apache.activemq.artemis.core.transaction.Transaction;
/**
* Used in tests to verify configuration passed into plugin correctly.
*/
public class ConfigurationVerifier implements ActiveMQServerPlugin, Serializable {
public static final String PROPERTY1 = "property1";
public static final String PROPERTY2 = "property2";
public static final String PROPERTY3 = "property3";
public String value1;
public String value2;
public String value3;
public AtomicInteger afterSendCounter = new AtomicInteger();
@Override
public void init(Map<String, String> properties) {
value1 = properties.get(PROPERTY1);
value2 = properties.get(PROPERTY2);
value3 = properties.get(PROPERTY3);
}
/**
* Used to ensure the plugin is being invoked
*/
@Override
public void afterSend(ServerSession session,
Transaction tx,
Message message,
boolean direct,
boolean noAutoCreateQueue,
RoutingStatus result) throws ActiveMQException {
afterSendCounter.incrementAndGet();
}
}

View File

@ -76,12 +76,17 @@ public class CorePluginTest extends JMSTestBase {
private final Map<String, AtomicInteger> methodCalls = new HashMap<>(); private final Map<String, AtomicInteger> methodCalls = new HashMap<>();
private final MethodCalledVerifier verifier = new MethodCalledVerifier(methodCalls); private final MethodCalledVerifier verifier = new MethodCalledVerifier(methodCalls);
private final ConfigurationVerifier configurationVerifier = new ConfigurationVerifier();
public static final String INVM_CONNECTOR_FACTORY = InVMConnectorFactory.class.getCanonicalName(); public static final String INVM_CONNECTOR_FACTORY = InVMConnectorFactory.class.getCanonicalName();
@Override @Override
protected Configuration createDefaultConfig(boolean netty) throws Exception { protected Configuration createDefaultConfig(boolean netty) throws Exception {
Configuration config = super.createDefaultConfig(netty); Configuration config = super.createDefaultConfig(netty);
config.registerBrokerPlugin(verifier); config.registerBrokerPlugin(verifier);
Map<String, String> props = new HashMap<>(1);
props.put(ConfigurationVerifier.PROPERTY1, "val_1");
configurationVerifier.init(props);
config.registerBrokerPlugin(configurationVerifier);
config.setMessageExpiryScanPeriod(0); // disable expiry scan so it's alwyas through delivery config.setMessageExpiryScanPeriod(0); // disable expiry scan so it's alwyas through delivery
return config; return config;
} }
@ -118,6 +123,9 @@ public class CorePluginTest extends JMSTestBase {
AFTER_MESSAGE_ROUTE); AFTER_MESSAGE_ROUTE);
verifier.validatePluginMethodsEquals(2, BEFORE_CREATE_SESSION, AFTER_CREATE_SESSION, BEFORE_CLOSE_SESSION, verifier.validatePluginMethodsEquals(2, BEFORE_CREATE_SESSION, AFTER_CREATE_SESSION, BEFORE_CLOSE_SESSION,
AFTER_CLOSE_SESSION); AFTER_CLOSE_SESSION);
assertEquals("configurationVerifier is invoked", 1, configurationVerifier.afterSendCounter.get());
assertEquals("configurationVerifier config set", "val_1", configurationVerifier.value1);
} }
@Test @Test

View File

@ -38,8 +38,13 @@ public class XmlConfigPluginTest extends ActiveMQTestBase {
ActiveMQServer server = addServer(new ActiveMQServerImpl(fc)); ActiveMQServer server = addServer(new ActiveMQServerImpl(fc));
try { try {
server.start(); server.start();
assertEquals(1, server.getBrokerPlugins().size()); assertEquals(2, server.getBrokerPlugins().size());
assertTrue(server.getBrokerPlugins().get(0) instanceof MethodCalledVerifier); assertTrue(server.getBrokerPlugins().get(0) instanceof MethodCalledVerifier);
assertTrue(server.getBrokerPlugins().get(1) instanceof ConfigurationVerifier);
ConfigurationVerifier configurationVerifier = (ConfigurationVerifier) server.getBrokerPlugins().get(1);
assertEquals("value1", "val_1", configurationVerifier.value1);
assertEquals("value2", "val_2", configurationVerifier.value2);
assertNull("value3 should not have been set", configurationVerifier.value3);
} finally { } finally {
if (server != null) { if (server != null) {
server.stop(); server.stop();

View File

@ -42,6 +42,10 @@
<broker-plugins> <broker-plugins>
<broker-plugin class-name="org.apache.activemq.artemis.tests.integration.plugin.MethodCalledVerifier" /> <broker-plugin class-name="org.apache.activemq.artemis.tests.integration.plugin.MethodCalledVerifier" />
<broker-plugin class-name="org.apache.activemq.artemis.tests.integration.plugin.ConfigurationVerifier">
<property key="property1" value="val_1"/>
<property key="property2" value="val_2"/>
</broker-plugin>
</broker-plugins> </broker-plugins>
</core> </core>