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
*/
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 d7b388d6b8..6eb6146aff 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:
+ *
+ * - name: {@link #NAME}
+ *
- queue-name: {@link #QUEUE_NAME}
+ *
- forwarding-address: {@link #FORWARDING_ADDRESS}
+ *
- filter-string: {@link #FILTER_STRING}
+ *
- static-connectors: {@link #STATIC_CONNECTORS}
+ *
- discovery-group-name: {@link #DISCOVERY_GROUP_NAME}
+ *
- ha: {@link #HA}
+ *
- transformer-configuration: {@link #TRANSFORMER_CONFIGURATION}
+ *
- retry-interval: {@link #RETRY_INTERVAL}
+ *
- RETRY-interval-multiplier: {@link #RETRY_INTERVAL_MULTIPLIER}
+ *
- initial-connect-attempts: {@link #INITIAL_CONNECT_ATTEMPTS}
+ *
- reconnect-attempts: {@link #RECONNECT_ATTEMPTS}
+ *
- reconnect-attempts-on-same-node: {@link #RECONNECT_ATTEMPTS_ON_SAME_NODE}
+ *
- use-duplicate-detection: {@link #USE_DUPLICATE_DETECTION}
+ *
- confirmation-window-size: {@link #CONFIRMATION_WINDOW_SIZE}
+ *
- producer-window-size: {@link #PRODUCER_WINDOW_SIZE}
+ *
- client-failure-check-period: {@link #CLIENT_FAILURE_CHECK_PERIOD}
+ *
- user: {@link #USER}
+ *
- password: {@link #PASSWORD}
+ *
- connection-ttl: {@link #CONNECTION_TTL}
+ *
- max-retry-interval: {@link #MAX_RETRY_INTERVAL}
+ *
- min-large-message-size: {@link #MIN_LARGE_MESSAGE_SIZE}
+ *
- call-timeout: {@link #CALL_TIMEOUT}
+ *
- routing-type: {@link #ROUTING_TYPE}
+ *
+ * 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 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 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 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 8306a6dea8..b1783a634d 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
@@ -3822,6 +3822,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()) {
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 0000000000..17a8050781
--- /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 7ae3606634..1a887979ce 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;
@@ -1878,6 +1880,96 @@ public class ActiveMQServerControlTest extends ManagementTestBase {
locator.close();
}
+ @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");
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 882e5caf40..c7719550bb 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
@@ -1556,6 +1556,11 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes
proxy.invokeOperation("createBridge", name, queueName, forwardingAddress, filterString, transformerClassName, retryInterval, retryIntervalMultiplier, initialConnectAttempts, reconnectAttempts, useDuplicateDetection, confirmationWindowSize, clientFailureCheckPeriod, connectorNames, useDiscovery, ha, user, password);
}
+ @Override
+ public void createBridge(String bridgeConfiguration) throws Exception {
+ proxy.invokeOperation("createBridge", bridgeConfiguration);
+ }
+
@Override
public String listProducersInfoAsJSON() throws Exception {
return (String) proxy.invokeOperation("listProducersInfoAsJSON");