You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2021/02/02 00:21:56 UTC
[activemq-artemis] branch master updated: ARTEMIS-3074 Add
ActiveMQServerControl#createBridge() method variant accepting a JSON string
This is an automated email from the ASF dual-hosted git repository.
clebertsuconic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/master by this push:
new ebeea15 ARTEMIS-3074 Add ActiveMQServerControl#createBridge() method variant accepting a JSON string
new 386aaa0 This closes #3412
ebeea15 is described below
commit ebeea15c2a8568952be8af2c4567ca5cf39898a8
Author: Tomas Hofman <th...@redhat.com>
AuthorDate: Tue Jan 19 15:04:35 2021 +0100
ARTEMIS-3074 Add ActiveMQServerControl#createBridge() method variant accepting a JSON string
---
.../api/core/management/ActiveMQServerControl.java | 24 ++
.../core/config/TransformerConfiguration.java | 47 +++-
.../artemis/core/config/BridgeConfiguration.java | 251 +++++++++++++++++++++
.../management/impl/ActiveMQServerControlImpl.java | 23 ++
.../core/config/BridgeConfigurationTest.java | 194 ++++++++++++++++
.../management/ActiveMQServerControlTest.java | 92 ++++++++
.../ActiveMQServerControlUsingCoreTest.java | 5 +
7 files changed, 635 insertions(+), 1 deletion(-)
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
index e981444..7668b65 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
@@ -1679,6 +1679,10 @@ public interface ActiveMQServerControl {
@Attribute(desc = "Names of the bridges deployed on this server")
String[] getBridgeNames();
+ /**
+ * @deprecated Deprecated in favour of {@link #createBridge(String)}
+ */
+ @Deprecated
@Operation(desc = "Create a Bridge", impact = MBeanOperationInfo.ACTION)
void createBridge(@Parameter(name = "name", desc = "Name of the bridge") String name,
@Parameter(name = "queueName", desc = "Name of the source queue") String queueName,
@@ -1699,6 +1703,10 @@ public interface ActiveMQServerControl {
@Parameter(name = "user", desc = "User name") String user,
@Parameter(name = "password", desc = "User password") String password) throws Exception;
+ /**
+ * @deprecated Deprecated in favour of {@link #createBridge(String)}
+ */
+ @Deprecated
@Operation(desc = "Create a Bridge", impact = MBeanOperationInfo.ACTION)
void createBridge(@Parameter(name = "name", desc = "Name of the bridge") String name,
@Parameter(name = "queueName", desc = "Name of the source queue") String queueName,
@@ -1720,6 +1728,10 @@ public interface ActiveMQServerControl {
@Parameter(name = "user", desc = "User name") String user,
@Parameter(name = "password", desc = "User password") String password) throws Exception;
+ /**
+ * @deprecated Deprecated in favour of {@link #createBridge(String)}
+ */
+ @Deprecated
@Operation(desc = "Create a Bridge", impact = MBeanOperationInfo.ACTION)
void createBridge(@Parameter(name = "name", desc = "Name of the bridge") String name,
@Parameter(name = "queueName", desc = "Name of the source queue") String queueName,
@@ -1741,6 +1753,10 @@ public interface ActiveMQServerControl {
@Parameter(name = "user", desc = "User name") String user,
@Parameter(name = "password", desc = "User password") String password) throws Exception;
+ /**
+ * @deprecated Deprecated in favour of {@link #createBridge(String)}
+ */
+ @Deprecated
@Operation(desc = "Create a Bridge", impact = MBeanOperationInfo.ACTION)
void createBridge(@Parameter(name = "name", desc = "Name of the bridge") String name,
@Parameter(name = "queueName", desc = "Name of the source queue") String queueName,
@@ -1760,6 +1776,14 @@ public interface ActiveMQServerControl {
@Parameter(name = "user", desc = "User name") String user,
@Parameter(name = "password", desc = "User password") String password) throws Exception;
+ /**
+ * Create a bridge.
+ *
+ * @param bridgeConfiguration the configuration of the queue in JSON format
+ */
+ @Operation(desc = "Create a bridge", impact = MBeanOperationInfo.ACTION)
+ void createBridge(@Parameter(name = "bridgeConfiguration", desc = "the configuration of the bridge in JSON format") String bridgeConfiguration) throws Exception;
+
@Operation(desc = "Destroy a bridge", impact = MBeanOperationInfo.ACTION)
void destroyBridge(@Parameter(name = "name", desc = "Name of the bridge") String name) throws Exception;
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/config/TransformerConfiguration.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/config/TransformerConfiguration.java
index 36c9960..1819679 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/config/TransformerConfiguration.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/config/TransformerConfiguration.java
@@ -16,7 +16,13 @@
*/
package org.apache.activemq.artemis.core.config;
+import org.apache.activemq.artemis.utils.JsonLoader;
+
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
import java.io.Serializable;
+import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
@@ -24,8 +30,10 @@ public final class TransformerConfiguration implements Serializable {
private static final long serialVersionUID = -1057244274380572226L;
- private final String className;
+ public static final String CLASS_NAME = "class-name";
+ public static final String PROPERTIES = "properties";
+ private final String className;
private Map<String, String> properties = new HashMap<>();
public TransformerConfiguration(String className) {
@@ -41,6 +49,43 @@ public final class TransformerConfiguration implements Serializable {
}
/**
+ * This method returns a {@code TransformerConfiguration} created from the JSON-formatted input {@code String}.
+ * The input should contain these entries:
+ *
+ * <p><ul>
+ * <li>class-name - a string value,
+ * <li>properties - an object containing string key-value pairs.
+ * </ul></p>
+ *
+ * @param jsonString json string
+ * @return the {@code TransformerConfiguration} created from the JSON-formatted input {@code String}
+ */
+ public static TransformerConfiguration fromJSON(String jsonString) {
+ JsonObject json = JsonLoader.readObject(new StringReader(jsonString));
+
+ // name is the only required value
+ if (!json.containsKey(CLASS_NAME)) {
+ return null;
+ }
+
+ TransformerConfiguration result = new TransformerConfiguration(json.getString(CLASS_NAME));
+
+ if (json.containsKey(PROPERTIES)) {
+ HashMap<String, String> properties = new HashMap<>();
+ for (Map.Entry<String, JsonValue> propEntry: json.getJsonObject(PROPERTIES).entrySet()) {
+ if (propEntry.getValue().getValueType() == JsonValue.ValueType.STRING) {
+ properties.put(propEntry.getKey(), ((JsonString) propEntry.getValue()).getString());
+ } else {
+ properties.put(propEntry.getKey(), propEntry.getValue().toString());
+ }
+ }
+ result.setProperties(properties);
+ }
+
+ return result;
+ }
+
+ /**
* @param properties the properties to set
*/
public TransformerConfiguration setProperties(final Map<String, String> properties) {
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/BridgeConfiguration.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/BridgeConfiguration.java
index d7b388d..6eb6146 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/BridgeConfiguration.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/BridgeConfiguration.java
@@ -16,17 +16,51 @@
*/
package org.apache.activemq.artemis.core.config;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonString;
+import javax.json.JsonValue;
import java.io.Serializable;
+import java.io.StringReader;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.core.server.ComponentConfigurationRoutingType;
+import org.apache.activemq.artemis.utils.JsonLoader;
public final class BridgeConfiguration implements Serializable {
private static final long serialVersionUID = -1057244274380572226L;
+ public static String NAME = "name";
+ public static String QUEUE_NAME = "queue-name";
+ public static String FORWARDING_ADDRESS = "forwarding-address";
+ public static String FILTER_STRING = "filter-string";
+ public static String STATIC_CONNECTORS = "static-connectors";
+ public static String DISCOVERY_GROUP_NAME = "discovery-group-name";
+ public static String HA = "ha";
+ public static String TRANSFORMER_CONFIGURATION = "transformer-configuration";
+ public static String RETRY_INTERVAL = "retry-interval";
+ public static String RETRY_INTERVAL_MULTIPLIER = "retry-interval-multiplier";
+ public static String INITIAL_CONNECT_ATTEMPTS = "initial-connect-attempts";
+ public static String RECONNECT_ATTEMPTS = "reconnect-attempts";
+ public static String RECONNECT_ATTEMPTS_ON_SAME_NODE = "reconnect-attempts-on-same-node";
+ public static String USE_DUPLICATE_DETECTION = "use-duplicate-detection";
+ public static String CONFIRMATION_WINDOW_SIZE = "confirmation-window-size";
+ public static String PRODUCER_WINDOW_SIZE = "producer-window-size";
+ public static String CLIENT_FAILURE_CHECK_PERIOD = "client-failure-check-period";
+ public static String USER = "user";
+ public static String PASSWORD = "password";
+ public static String CONNECTION_TTL = "connection-ttl";
+ public static String MAX_RETRY_INTERVAL = "max-retry-interval";
+ public static String MIN_LARGE_MESSAGE_SIZE = "min-large-message-size";
+ public static String CALL_TIMEOUT = "call-timeout";
+ public static String ROUTING_TYPE = "routing-type";
+
private String name = null;
private String queueName = null;
@@ -81,6 +115,110 @@ public final class BridgeConfiguration implements Serializable {
public BridgeConfiguration() {
}
+ public BridgeConfiguration(String name) {
+ setName(name);
+ }
+
+ /**
+ * Set the value of a parameter based on its "key" {@code String}. Valid key names and corresponding {@code static}
+ * {@code final} are:
+ * <p><ul>
+ * <li>name: {@link #NAME}
+ * <li>queue-name: {@link #QUEUE_NAME}
+ * <li>forwarding-address: {@link #FORWARDING_ADDRESS}
+ * <li>filter-string: {@link #FILTER_STRING}
+ * <li>static-connectors: {@link #STATIC_CONNECTORS}
+ * <li>discovery-group-name: {@link #DISCOVERY_GROUP_NAME}
+ * <li>ha: {@link #HA}
+ * <li>transformer-configuration: {@link #TRANSFORMER_CONFIGURATION}
+ * <li>retry-interval: {@link #RETRY_INTERVAL}
+ * <li>RETRY-interval-multiplier: {@link #RETRY_INTERVAL_MULTIPLIER}
+ * <li>initial-connect-attempts: {@link #INITIAL_CONNECT_ATTEMPTS}
+ * <li>reconnect-attempts: {@link #RECONNECT_ATTEMPTS}
+ * <li>reconnect-attempts-on-same-node: {@link #RECONNECT_ATTEMPTS_ON_SAME_NODE}
+ * <li>use-duplicate-detection: {@link #USE_DUPLICATE_DETECTION}
+ * <li>confirmation-window-size: {@link #CONFIRMATION_WINDOW_SIZE}
+ * <li>producer-window-size: {@link #PRODUCER_WINDOW_SIZE}
+ * <li>client-failure-check-period: {@link #CLIENT_FAILURE_CHECK_PERIOD}
+ * <li>user: {@link #USER}
+ * <li>password: {@link #PASSWORD}
+ * <li>connection-ttl: {@link #CONNECTION_TTL}
+ * <li>max-retry-interval: {@link #MAX_RETRY_INTERVAL}
+ * <li>min-large-message-size: {@link #MIN_LARGE_MESSAGE_SIZE}
+ * <li>call-timeout: {@link #CALL_TIMEOUT}
+ * <li>routing-type: {@link #ROUTING_TYPE}
+ * </ul><p>
+ * The {@code String}-based values will be converted to the proper value types based on the underlying property. For
+ * example, if you pass the value "TRUE" for the key "auto-created" the {@code String} "TRUE" will be converted to
+ * the {@code Boolean} {@code true}.
+ *
+ * @param key the key to set to the value
+ * @param value the value to set for the key
+ * @return this {@code BridgeConfiguration}
+ */
+ public BridgeConfiguration set(String key, String value) {
+ if (key != null) {
+ if (key.equals(NAME)) {
+ setName(value);
+ } else if (key.equals(QUEUE_NAME)) {
+ setQueueName(value);
+ } else if (key.equals(FORWARDING_ADDRESS)) {
+ setForwardingAddress(value);
+ } else if (key.equals(FILTER_STRING)) {
+ setFilterString(value);
+ } else if (key.equals(STATIC_CONNECTORS)) {
+ // convert JSON array to string list
+ List<String> stringList = JsonLoader.readArray(new StringReader(value)).stream()
+ .map(v -> ((JsonString) v).getString())
+ .collect(Collectors.toList());
+ setStaticConnectors(stringList);
+ } else if (key.equals(DISCOVERY_GROUP_NAME)) {
+ setDiscoveryGroupName(value);
+ } else if (key.equals(HA)) {
+ setHA(Boolean.parseBoolean(value));
+ } else if (key.equals(TRANSFORMER_CONFIGURATION)) {
+ // create a transformer instance from a JSON string
+ TransformerConfiguration transformerConfiguration = TransformerConfiguration.fromJSON(value);
+ if (transformerConfiguration != null) {
+ setTransformerConfiguration(transformerConfiguration);
+ }
+ } else if (key.equals(RETRY_INTERVAL)) {
+ setRetryInterval(Long.parseLong(value));
+ } else if (key.equals(RETRY_INTERVAL_MULTIPLIER)) {
+ setRetryIntervalMultiplier(Double.parseDouble(value));
+ } else if (key.equals(INITIAL_CONNECT_ATTEMPTS)) {
+ setInitialConnectAttempts(Integer.parseInt(value));
+ } else if (key.equals(RECONNECT_ATTEMPTS)) {
+ setReconnectAttempts(Integer.parseInt(value));
+ } else if (key.equals(RECONNECT_ATTEMPTS_ON_SAME_NODE)) {
+ setReconnectAttemptsOnSameNode(Integer.parseInt(value));
+ } else if (key.equals(USE_DUPLICATE_DETECTION)) {
+ setUseDuplicateDetection(Boolean.parseBoolean(value));
+ } else if (key.equals(CONFIRMATION_WINDOW_SIZE)) {
+ setConfirmationWindowSize(Integer.parseInt(value));
+ } else if (key.equals(PRODUCER_WINDOW_SIZE)) {
+ setProducerWindowSize(Integer.parseInt(value));
+ } else if (key.equals(CLIENT_FAILURE_CHECK_PERIOD)) {
+ setClientFailureCheckPeriod(Long.parseLong(value));
+ } else if (key.equals(USER)) {
+ setUser(value);
+ } else if (key.equals(PASSWORD)) {
+ setPassword(value);
+ } else if (key.equals(CONNECTION_TTL)) {
+ setConnectionTTL(Long.parseLong(value));
+ } else if (key.equals(MAX_RETRY_INTERVAL)) {
+ setMaxRetryInterval(Long.parseLong(value));
+ } else if (key.equals(MIN_LARGE_MESSAGE_SIZE)) {
+ setMinLargeMessageSize(Integer.parseInt(value));
+ } else if (key.equals(CALL_TIMEOUT)) {
+ setCallTimeout(Long.parseLong(value));
+ } else if (key.equals(ROUTING_TYPE)) {
+ setRoutingType(ComponentConfigurationRoutingType.valueOf(value));
+ }
+ }
+ return this;
+ }
+
public String getName() {
return name;
}
@@ -360,6 +498,119 @@ public final class BridgeConfiguration implements Serializable {
return this;
}
+ /**
+ * This method returns a JSON-formatted {@code String} representation of this {@code BridgeConfiguration}. It is a
+ * simple collection of key/value pairs. The keys used are referenced in {@link #set(String, String)}.
+ *
+ * @return a JSON-formatted {@code String} representation of this {@code BridgeConfiguration}
+ */
+ public String toJSON() {
+ JsonObjectBuilder builder = JsonLoader.createObjectBuilder();
+
+ // string fields which default to null (only serialize if value is not null)
+
+ if (getName() != null) {
+ builder.add(NAME, getName());
+ }
+ if (getQueueName() != null) {
+ builder.add(QUEUE_NAME, getQueueName());
+ }
+ if (getForwardingAddress() != null) {
+ builder.add(FORWARDING_ADDRESS, getForwardingAddress());
+ }
+ if (getFilterString() != null) {
+ builder.add(FILTER_STRING, getFilterString());
+ }
+ if (getDiscoveryGroupName() != null) {
+ builder.add(DISCOVERY_GROUP_NAME, getDiscoveryGroupName());
+ }
+
+ // string fields which default to non-null values (always serialize)
+
+ addNullable(builder, USER, getUser());
+ addNullable(builder, PASSWORD, getPassword());
+
+ // primitive data type fields (always serialize)
+
+ builder.add(HA, isHA());
+ builder.add(RETRY_INTERVAL, getRetryInterval());
+ builder.add(RETRY_INTERVAL_MULTIPLIER, getRetryIntervalMultiplier());
+ builder.add(INITIAL_CONNECT_ATTEMPTS, getInitialConnectAttempts());
+ builder.add(RECONNECT_ATTEMPTS, getReconnectAttempts());
+ builder.add(RECONNECT_ATTEMPTS_ON_SAME_NODE, getReconnectAttemptsOnSameNode());
+ builder.add(USE_DUPLICATE_DETECTION, isUseDuplicateDetection());
+ builder.add(CONFIRMATION_WINDOW_SIZE, getConfirmationWindowSize());
+ builder.add(PRODUCER_WINDOW_SIZE, getProducerWindowSize());
+ builder.add(CLIENT_FAILURE_CHECK_PERIOD, getClientFailureCheckPeriod());
+ builder.add(CONNECTION_TTL, getConnectionTTL());
+ builder.add(MAX_RETRY_INTERVAL, getMaxRetryInterval());
+ builder.add(MIN_LARGE_MESSAGE_SIZE, getMinLargeMessageSize());
+ builder.add(CALL_TIMEOUT, getCallTimeout());
+
+ // complex fields (only serialize if value is not null)
+
+ if (getRoutingType() != null) {
+ builder.add(ROUTING_TYPE, getRoutingType().name());
+ }
+
+ final List<String> staticConnectors = getStaticConnectors();
+ if (staticConnectors != null) {
+ JsonArrayBuilder arrayBuilder = JsonLoader.createArrayBuilder();
+ staticConnectors.forEach(arrayBuilder::add);
+ builder.add(STATIC_CONNECTORS, arrayBuilder);
+ }
+
+ TransformerConfiguration tc = getTransformerConfiguration();
+ if (tc != null) {
+ JsonObjectBuilder tcBuilder = JsonLoader.createObjectBuilder().add(TransformerConfiguration.CLASS_NAME, tc.getClassName());
+ if (tc.getProperties() != null && tc.getProperties().size() > 0) {
+ JsonObjectBuilder propBuilder = JsonLoader.createObjectBuilder();
+ tc.getProperties().forEach(propBuilder::add);
+ tcBuilder.add(TransformerConfiguration.PROPERTIES, propBuilder);
+ }
+ builder.add(TRANSFORMER_CONFIGURATION, tcBuilder);
+ }
+
+ return builder.build().toString();
+ }
+
+ private static void addNullable(JsonObjectBuilder builder, String key, String value) {
+ if (value == null) {
+ builder.addNull(key);
+ } else {
+ builder.add(key, value);
+ }
+ }
+
+ /**
+ * This method returns a {@code BridgeConfiguration} created from the JSON-formatted input {@code String}. The input
+ * should be a simple object of key/value pairs. Valid keys are referenced in {@link #set(String, String)}.
+ *
+ * @param jsonString json string
+ * @return the {@code BridgeConfiguration} created from the JSON-formatted input {@code String}
+ */
+ public static BridgeConfiguration fromJSON(String jsonString) {
+ JsonObject json = JsonLoader.readObject(new StringReader(jsonString));
+
+ // name is the only required value
+ if (!json.containsKey(NAME)) {
+ return null;
+ }
+ BridgeConfiguration result = new BridgeConfiguration(json.getString(NAME));
+
+ for (Map.Entry<String, JsonValue> entry : json.entrySet()) {
+ if (entry.getValue().getValueType() == JsonValue.ValueType.STRING) {
+ result.set(entry.getKey(), ((JsonString) entry.getValue()).getString());
+ } else if (entry.getValue().getValueType() == JsonValue.ValueType.NULL) {
+ result.set(entry.getKey(), null);
+ } else {
+ result.set(entry.getKey(), entry.getValue().toString());
+ }
+ }
+
+ return result;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java
index 8306a6d..b1783a6 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java
@@ -3823,6 +3823,29 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
}
@Override
+ public void createBridge(String bridgeConfigurationAsJson) throws Exception {
+ if (AuditLogger.isEnabled()) {
+ AuditLogger.createBridge(this.server, bridgeConfigurationAsJson);
+ }
+ checkStarted();
+
+ clearIO();
+
+ try {
+ // when the BridgeConfiguration is passed through createBridge all of its defaults get set which we return to the caller
+ BridgeConfiguration bridgeConfiguration = BridgeConfiguration.fromJSON(bridgeConfigurationAsJson);
+ if (bridgeConfiguration == null) {
+ throw ActiveMQMessageBundle.BUNDLE.failedToParseJson(bridgeConfigurationAsJson);
+ }
+ server.deployBridge(bridgeConfiguration);
+ } catch (ActiveMQException e) {
+ throw new IllegalStateException(e.getMessage());
+ } finally {
+ blockOnIO();
+ }
+ }
+
+ @Override
public String listBrokerConnections() {
if (AuditLogger.isEnabled()) {
AuditLogger.listBrokerConnections();
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/BridgeConfigurationTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/BridgeConfigurationTest.java
new file mode 100644
index 0000000..17a8050
--- /dev/null
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/BridgeConfigurationTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.core.config;
+
+import org.apache.activemq.artemis.core.server.ComponentConfigurationRoutingType;
+import org.apache.activemq.artemis.utils.JsonLoader;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+import javax.json.spi.JsonProvider;
+import java.io.StringReader;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+
+public class BridgeConfigurationTest {
+
+ @Test
+ public void testFromJSON() {
+ String jsonString = createFullJsonObject().toString();
+
+ BridgeConfiguration bridgeConfiguration = BridgeConfiguration.fromJSON(jsonString);
+
+ Assert.assertNotNull(bridgeConfiguration);
+ Assert.assertEquals("name", bridgeConfiguration.getName());
+ Assert.assertEquals("queue-name", bridgeConfiguration.getQueueName());
+ Assert.assertEquals("forwarding-address", bridgeConfiguration.getForwardingAddress());
+ Assert.assertEquals("filter-string", bridgeConfiguration.getFilterString());
+ Assert.assertArrayEquals(new String[]{"connector1", "connector2"},
+ bridgeConfiguration.getStaticConnectors().toArray());
+ Assert.assertEquals("dg", bridgeConfiguration.getDiscoveryGroupName());
+ Assert.assertTrue(bridgeConfiguration.isHA());
+ Assert.assertEquals("ClassName", bridgeConfiguration.getTransformerConfiguration().getClassName());
+ Assert.assertThat(bridgeConfiguration.getTransformerConfiguration().getProperties().keySet(), containsInAnyOrder("prop1", "prop2"));
+ Assert.assertEquals("val1", bridgeConfiguration.getTransformerConfiguration().getProperties().get("prop1"));
+ Assert.assertEquals("val2", bridgeConfiguration.getTransformerConfiguration().getProperties().get("prop2"));
+ Assert.assertEquals(1, bridgeConfiguration.getRetryInterval());
+ Assert.assertEquals(2.0, bridgeConfiguration.getRetryIntervalMultiplier(), 0);
+ Assert.assertEquals(3, bridgeConfiguration.getInitialConnectAttempts());
+ Assert.assertEquals(4, bridgeConfiguration.getReconnectAttempts());
+ Assert.assertEquals(5, bridgeConfiguration.getReconnectAttemptsOnSameNode());
+ Assert.assertTrue(bridgeConfiguration.isUseDuplicateDetection());
+ Assert.assertEquals(6, bridgeConfiguration.getConfirmationWindowSize());
+ Assert.assertEquals(7, bridgeConfiguration.getProducerWindowSize());
+ Assert.assertEquals(8, bridgeConfiguration.getClientFailureCheckPeriod());
+ Assert.assertEquals("user", bridgeConfiguration.getUser());
+ Assert.assertEquals("password", bridgeConfiguration.getPassword());
+ Assert.assertEquals(9, bridgeConfiguration.getConnectionTTL());
+ Assert.assertEquals(10, bridgeConfiguration.getMaxRetryInterval());
+ Assert.assertEquals(11, bridgeConfiguration.getMinLargeMessageSize());
+ Assert.assertEquals(12, bridgeConfiguration.getCallTimeout());
+ Assert.assertEquals(ComponentConfigurationRoutingType.MULTICAST, bridgeConfiguration.getRoutingType());
+ }
+
+ @Test
+ public void testToJSON() {
+ // create bc instance from a JSON object, all attributes are set
+ JsonObject jsonObject = createFullJsonObject();
+ BridgeConfiguration bridgeConfiguration = BridgeConfiguration.fromJSON(jsonObject.toString());
+ Assert.assertNotNull(bridgeConfiguration);
+
+ // serialize it back to JSON
+ String serializedBridgeConfiguration = bridgeConfiguration.toJSON();
+ JsonObject serializedBridgeConfigurationJsonObject = JsonLoader.readObject(new StringReader(serializedBridgeConfiguration));
+
+ // verify that the original JSON object is identical to the one serialized via the toJSON() method
+ Assert.assertEquals(jsonObject, serializedBridgeConfigurationJsonObject);
+ }
+
+ @Test
+ public void testDefaultsToJson() {
+ // create and serialize BridgeConfiguration instance without modifying any fields
+ BridgeConfiguration bridgeConfiguration = new BridgeConfiguration();
+ String jsonString = bridgeConfiguration.toJSON();
+ JsonObject jsonObject = JsonLoader.readObject(new StringReader(jsonString));
+
+ // the serialized JSON string should contain default values of primitive type fields
+ Assert.assertEquals("2000", jsonObject.get(BridgeConfiguration.RETRY_INTERVAL).toString());
+ Assert.assertEquals("1.0", jsonObject.get(BridgeConfiguration.RETRY_INTERVAL_MULTIPLIER).toString());
+ Assert.assertEquals("-1", jsonObject.get(BridgeConfiguration.INITIAL_CONNECT_ATTEMPTS).toString());
+ Assert.assertEquals("-1", jsonObject.get(BridgeConfiguration.RECONNECT_ATTEMPTS).toString());
+ Assert.assertEquals("10", jsonObject.get(BridgeConfiguration.RECONNECT_ATTEMPTS_ON_SAME_NODE).toString());
+ Assert.assertEquals("true", jsonObject.get(BridgeConfiguration.USE_DUPLICATE_DETECTION).toString());
+ Assert.assertEquals("-1", jsonObject.get(BridgeConfiguration.CONFIRMATION_WINDOW_SIZE).toString());
+ Assert.assertEquals("-1", jsonObject.get(BridgeConfiguration.PRODUCER_WINDOW_SIZE).toString());
+ Assert.assertEquals("30000", jsonObject.get(BridgeConfiguration.CLIENT_FAILURE_CHECK_PERIOD).toString());
+ Assert.assertEquals("2000", jsonObject.get(BridgeConfiguration.MAX_RETRY_INTERVAL).toString());
+ Assert.assertEquals("102400", jsonObject.get(BridgeConfiguration.MIN_LARGE_MESSAGE_SIZE).toString());
+ Assert.assertEquals("30000", jsonObject.get(BridgeConfiguration.CALL_TIMEOUT).toString());
+
+ // also should contain default non-null values of string fields
+ Assert.assertEquals("\"ACTIVEMQ.CLUSTER.ADMIN.USER\"", jsonObject.get(BridgeConfiguration.USER).toString());
+ Assert.assertEquals("\"CHANGE ME!!\"", jsonObject.get(BridgeConfiguration.PASSWORD).toString());
+ }
+
+ @Test
+ public void testDefaultsFromJson() {
+ // create BridgeConfiguration instance from empty JSON string
+ final String jsonString = "{\"name\": \"name\"}"; // name field is required
+ BridgeConfiguration deserializedConfiguration = BridgeConfiguration.fromJSON(jsonString);
+ Assert.assertNotNull(deserializedConfiguration);
+
+ // the deserialized object should return the same default values as a newly instantiated object
+ Assert.assertEquals(deserializedConfiguration, new BridgeConfiguration("name"));
+ }
+
+ @Test
+ public void testNullableFieldsFromJson() {
+ // set string fields which default value is not null to null
+ JsonObjectBuilder builder = JsonLoader.createObjectBuilder();
+ builder.add(BridgeConfiguration.NAME, "name"); // required field
+ builder.addNull(BridgeConfiguration.USER);
+ builder.addNull(BridgeConfiguration.PASSWORD);
+
+ BridgeConfiguration configuration = BridgeConfiguration.fromJSON(builder.build().toString());
+
+ // in deserialized object the fields should still remain null
+ Assert.assertNotNull(configuration);
+ Assert.assertEquals("name", configuration.getName());
+ Assert.assertNull(configuration.getUser());
+ Assert.assertNull(configuration.getPassword());
+ }
+
+ @Test
+ public void testNullableFieldsToJson() {
+ // set string fields which default value is not null to null
+ BridgeConfiguration bridgeConfiguration = new BridgeConfiguration("name");
+ bridgeConfiguration.setUser(null);
+ bridgeConfiguration.setPassword(null);
+
+ String jsonString = bridgeConfiguration.toJSON();
+ JsonObject jsonObject = JsonLoader.readObject(new StringReader(jsonString));
+
+ // after serialization the fields value should remain null
+ Assert.assertEquals(JsonValue.ValueType.NULL, jsonObject.get(BridgeConfiguration.USER).getValueType());
+ Assert.assertEquals(JsonValue.ValueType.NULL, jsonObject.get(BridgeConfiguration.PASSWORD).getValueType());
+ }
+
+ private static JsonObject createFullJsonObject() {
+ JsonObjectBuilder objectBuilder = JsonLoader.createObjectBuilder();
+
+ objectBuilder.add(BridgeConfiguration.NAME, "name");
+ objectBuilder.add(BridgeConfiguration.QUEUE_NAME, "queue-name");
+ objectBuilder.add(BridgeConfiguration.FORWARDING_ADDRESS, "forwarding-address");
+ objectBuilder.add(BridgeConfiguration.FILTER_STRING, "filter-string");
+ objectBuilder.add(BridgeConfiguration.STATIC_CONNECTORS,
+ JsonProvider.provider().createArrayBuilder()
+ .add("connector1")
+ .add("connector2"));
+ objectBuilder.add(BridgeConfiguration.DISCOVERY_GROUP_NAME, "dg");
+ objectBuilder.add(BridgeConfiguration.HA, true);
+ objectBuilder.add(BridgeConfiguration.TRANSFORMER_CONFIGURATION,
+ JsonLoader.createObjectBuilder()
+ .add("class-name", "ClassName")
+ .add("properties",
+ JsonLoader.createObjectBuilder()
+ .add("prop1", "val1")
+ .add("prop2", "val2")));
+ objectBuilder.add(BridgeConfiguration.RETRY_INTERVAL, 1);
+ objectBuilder.add(BridgeConfiguration.RETRY_INTERVAL_MULTIPLIER, 2.0);
+ objectBuilder.add(BridgeConfiguration.INITIAL_CONNECT_ATTEMPTS, 3);
+ objectBuilder.add(BridgeConfiguration.RECONNECT_ATTEMPTS, 4);
+ objectBuilder.add(BridgeConfiguration.RECONNECT_ATTEMPTS_ON_SAME_NODE, 5);
+ objectBuilder.add(BridgeConfiguration.USE_DUPLICATE_DETECTION, true);
+ objectBuilder.add(BridgeConfiguration.CONFIRMATION_WINDOW_SIZE, 6);
+ objectBuilder.add(BridgeConfiguration.PRODUCER_WINDOW_SIZE, 7);
+ objectBuilder.add(BridgeConfiguration.CLIENT_FAILURE_CHECK_PERIOD, 8);
+ objectBuilder.add(BridgeConfiguration.USER, "user");
+ objectBuilder.add(BridgeConfiguration.PASSWORD, "password");
+ objectBuilder.add(BridgeConfiguration.CONNECTION_TTL, 9);
+ objectBuilder.add(BridgeConfiguration.MAX_RETRY_INTERVAL, 10);
+ objectBuilder.add(BridgeConfiguration.MIN_LARGE_MESSAGE_SIZE, 11);
+ objectBuilder.add(BridgeConfiguration.CALL_TIMEOUT, 12);
+ objectBuilder.add(BridgeConfiguration.ROUTING_TYPE, "MULTICAST");
+
+ return objectBuilder.build();
+ }
+}
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java
index 7ae3606..1a88797 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java
@@ -28,6 +28,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -60,6 +61,7 @@ import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl;
import org.apache.activemq.artemis.core.client.impl.ClientSessionImpl;
+import org.apache.activemq.artemis.core.config.BridgeConfiguration;
import org.apache.activemq.artemis.core.config.ClusterConnectionConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
@@ -1879,6 +1881,96 @@ public class ActiveMQServerControlTest extends ManagementTestBase {
}
@Test
+ public void testCreateAndDestroyBridgeFromJson() throws Exception {
+ String name = RandomUtil.randomString();
+ String sourceAddress = RandomUtil.randomString();
+ String sourceQueue = RandomUtil.randomString();
+ String targetAddress = RandomUtil.randomString();
+ String targetQueue = RandomUtil.randomString();
+
+ ActiveMQServerControl serverControl = createManagementControl();
+
+ checkNoResource(ObjectNameBuilder.DEFAULT.getBridgeObjectName(name));
+ assertEquals(0, serverControl.getBridgeNames().length);
+
+ ServerLocator locator = createInVMNonHALocator();
+ ClientSessionFactory csf = createSessionFactory(locator);
+ ClientSession session = csf.createSession();
+
+ if (legacyCreateQueue) {
+ session.createQueue(sourceAddress, RoutingType.ANYCAST, sourceQueue);
+ session.createQueue(targetAddress, RoutingType.ANYCAST, targetQueue);
+ } else {
+ session.createQueue(new QueueConfiguration(sourceQueue).setAddress(sourceAddress).setRoutingType(RoutingType.ANYCAST).setDurable(false));
+ session.createQueue(new QueueConfiguration(targetQueue).setAddress(targetAddress).setRoutingType(RoutingType.ANYCAST).setDurable(false));
+ }
+
+ BridgeConfiguration bridgeConfiguration = new BridgeConfiguration(name)
+ .setQueueName(sourceQueue)
+ .setForwardingAddress(targetAddress)
+ .setUseDuplicateDetection(false)
+ .setConfirmationWindowSize(1)
+ .setProducerWindowSize(-1)
+ .setStaticConnectors(Collections.singletonList(connectorConfig.getName()))
+ .setHA(false)
+ .setUser(null)
+ .setPassword(null);
+ serverControl.createBridge(bridgeConfiguration.toJSON());
+
+ checkResource(ObjectNameBuilder.DEFAULT.getBridgeObjectName(name));
+ String[] bridgeNames = serverControl.getBridgeNames();
+ assertEquals(1, bridgeNames.length);
+ assertEquals(name, bridgeNames[0]);
+
+ BridgeControl bridgeControl = ManagementControlHelper.createBridgeControl(name, mbeanServer);
+ assertEquals(name, bridgeControl.getName());
+ assertTrue(bridgeControl.isStarted());
+
+ // check that a message sent to the sourceAddress is put in the tagetQueue
+ ClientProducer producer = session.createProducer(sourceAddress);
+ ClientMessage message = session.createMessage(false);
+ String text = RandomUtil.randomString();
+ message.putStringProperty("prop", text);
+ producer.send(message);
+
+ session.start();
+
+ ClientConsumer targetConsumer = session.createConsumer(targetQueue);
+ message = targetConsumer.receive(5000);
+ assertNotNull(message);
+ assertEquals(text, message.getStringProperty("prop"));
+
+ ClientConsumer sourceConsumer = session.createConsumer(sourceQueue);
+ assertNull(sourceConsumer.receiveImmediate());
+
+ serverControl.destroyBridge(name);
+
+ checkNoResource(ObjectNameBuilder.DEFAULT.getBridgeObjectName(name));
+ assertEquals(0, serverControl.getBridgeNames().length);
+
+ // check that a message is no longer diverted
+ message = session.createMessage(false);
+ String text2 = RandomUtil.randomString();
+ message.putStringProperty("prop", text2);
+ producer.send(message);
+
+ assertNull(targetConsumer.receiveImmediate());
+ message = sourceConsumer.receive(5000);
+ assertNotNull(message);
+ assertEquals(text2, message.getStringProperty("prop"));
+
+ sourceConsumer.close();
+ targetConsumer.close();
+
+ session.deleteQueue(sourceQueue);
+ session.deleteQueue(targetQueue);
+
+ session.close();
+
+ locator.close();
+ }
+
+ @Test
public void testListPreparedTransactionDetails() throws Exception {
SimpleString atestq = new SimpleString("BasicXaTestq");
Xid xid = newXID();
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java
index 882e5ca..c771955 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java
@@ -1557,6 +1557,11 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes
}
@Override
+ public void createBridge(String bridgeConfiguration) throws Exception {
+ proxy.invokeOperation("createBridge", bridgeConfiguration);
+ }
+
+ @Override
public String listProducersInfoAsJSON() throws Exception {
return (String) proxy.invokeOperation("listProducersInfoAsJSON");
}