ARTEMIS-3074 Add ActiveMQServerControl#createBridge() method variant accepting a JSON string

This commit is contained in:
Tomas Hofman 2021-01-19 15:04:35 +01:00 committed by Clebert Suconic
parent bd738e0e00
commit ebeea15c2a
7 changed files with 635 additions and 1 deletions

View File

@ -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;

View File

@ -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) {
@ -40,6 +48,43 @@ public final class TransformerConfiguration implements Serializable {
return properties;
}
/**
* 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
*/

View File

@ -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;

View File

@ -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()) {

View File

@ -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();
}
}

View File

@ -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");

View File

@ -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");