diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressConsumer.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressConsumer.java index 28602201be81..6c27bcd4357d 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressConsumer.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressConsumer.java @@ -17,9 +17,10 @@ package org.apache.activemq.artemis.protocol.amqp.connect.federation; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_ADDRESS_RECEIVER; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_POLICY_NAME; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationPolicySupport.FEDERATED_ADDRESS_SOURCE_PROPERTIES; @@ -154,11 +155,10 @@ protected final void doCreateReceiver() { target.setAddress(consumerInfo.getTargetAddress()); final Map addressSourceProperties = new HashMap<>(); - // If the remote needs to create the address then it should apply these - // settings during the create. - addressSourceProperties.put(ADDRESS_AUTO_DELETE, policy.isAutoDelete()); - addressSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); - addressSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); + addressSourceProperties.put(AUTO_CREATE, policy.isAutoCreate()); + addressSourceProperties.put(AUTO_DELETE, policy.isAutoDelete()); + addressSourceProperties.put(AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); + addressSourceProperties.put(AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); final Map receiverProperties = new HashMap<>(); receiverProperties.put(FEDERATED_ADDRESS_SOURCE_PROPERTIES, addressSourceProperties); diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressSenderController.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressSenderController.java index 063d345b2bd2..ca2987950b63 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressSenderController.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationAddressSenderController.java @@ -17,14 +17,21 @@ package org.apache.activemq.artemis.protocol.amqp.connect.federation; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_ADDRESS_RECEIVER; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_ADDRESS_AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationPolicySupport.FEDERATED_ADDRESS_SOURCE_PROPERTIES; + import java.lang.invoke.MethodHandles; import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Consumer; @@ -99,15 +106,17 @@ public ServerConsumer createServerConsumer(ProtonServerSenderContext senderConte final Map addressSourceProperties; - if (sender.getRemoteProperties() == null || !sender.getRemoteProperties().containsKey(FEDERATED_ADDRESS_SOURCE_PROPERTIES)) { + if (sender.getRemoteProperties() == null) { addressSourceProperties = Collections.emptyMap(); } else { - addressSourceProperties = (Map) sender.getRemoteProperties().get(FEDERATED_ADDRESS_SOURCE_PROPERTIES); + addressSourceProperties = (Map) + Objects.requireNonNullElse(sender.getRemoteProperties().get(FEDERATED_ADDRESS_SOURCE_PROPERTIES), Collections.emptyMap()); } - final boolean autoDelete = (boolean) addressSourceProperties.getOrDefault(ADDRESS_AUTO_DELETE, false); - final long autoDeleteDelay = ((Number) addressSourceProperties.getOrDefault(ADDRESS_AUTO_DELETE_DELAY, 0)).longValue(); - final long autoDeleteMsgCount = ((Number) addressSourceProperties.getOrDefault(ADDRESS_AUTO_DELETE_MSG_COUNT, 0)).longValue(); + final boolean autoCreate = (boolean) addressSourceProperties.getOrDefault(AUTO_CREATE, DEFAULT_ADDRESS_AUTO_CREATE); + final boolean autoDelete = (boolean) addressSourceProperties.getOrDefault(AUTO_DELETE, DEFAULT_AUTO_DELETE); + final long autoDeleteDelay = ((Number) addressSourceProperties.getOrDefault(AUTO_DELETE_DELAY, DEFAULT_AUTO_DELETE_DELAY)).longValue(); + final long autoDeleteMsgCount = ((Number) addressSourceProperties.getOrDefault(AUTO_DELETE_MSG_COUNT, DEFAULT_AUTO_DELETE_MSG_COUNT)).longValue(); // An address receiver may opt to filter on things like max message hops or no local message // reflection so we must check for a filter here and apply it if it exists. @@ -142,7 +151,7 @@ public ServerConsumer createServerConsumer(ProtonServerSenderContext senderConte final AddressQueryResult addressQueryResult; try { - addressQueryResult = sessionSPI.addressQuery(address, RoutingType.MULTICAST, true); + addressQueryResult = sessionSPI.addressQuery(address, RoutingType.MULTICAST, autoCreate); } catch (ActiveMQSecurityException e) { throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.securityErrorCreatingConsumer(e.getMessage()); } catch (ActiveMQAMQPException e) { diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConfiguration.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConfiguration.java index c0312d89f243..6aa6f7be909f 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConfiguration.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConfiguration.java @@ -31,7 +31,6 @@ import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.RECEIVER_LINK_QUIESCE_TIMEOUT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.RECEIVER_QUIESCE_TIMEOUT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.USE_MODIFIED_FOR_TRANSIENT_DELIVERY_ERRORS; - import java.util.Collections; import java.util.HashMap; import java.util.Map; diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConstants.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConstants.java index e5cc4f9c10a7..ae50d636e119 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConstants.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationConstants.java @@ -273,30 +273,35 @@ public final class AMQPFederationConstants { */ public static final String ADDRESS_EXCLUDES = "address-excludes"; + /** + * Encodes a boolean value that indicates if federated resource auto creation should be enabled. + */ + public static final String AUTO_CREATE = "auto-create"; + /** * Encodes a boolean value that indicates if queue auto delete option should be enabled. */ - public static final String ADDRESS_AUTO_DELETE = "auto-delete"; + public static final String AUTO_DELETE = "auto-delete"; /** * Encodes a signed long value that controls the delay before auto deletion if auto delete is enabled. */ - public static final String ADDRESS_AUTO_DELETE_DELAY = "auto-delete-delay"; + public static final String AUTO_DELETE_DELAY = "auto-delete-delay"; /** - * Encodes a signed long value that controls the message count value that allows for address auto delete. + * Encodes a signed long value that controls the message count value that allows for auto delete when enabled. */ - public static final String ADDRESS_AUTO_DELETE_MSG_COUNT = "auto-delete-msg-count"; + public static final String AUTO_DELETE_MSG_COUNT = "auto-delete-msg-count"; /** * Encodes a signed integer value that controls the maximum number of hops allowed for federated messages. */ - public static final String ADDRESS_MAX_HOPS = "max-hops"; + public static final String MAX_HOPS = "max-hops"; /** * Encodes boolean value that controls if the address federation should include divert bindings. */ - public static final String ADDRESS_ENABLE_DIVERT_BINDINGS = "enable-divert-bindings"; + public static final String ENABLE_DIVERT_BINDINGS = "enable-divert-bindings"; /** * Encodes a boolean value that controls if the address federation should check the matcher value in the @@ -304,7 +309,7 @@ public final class AMQPFederationConstants { * the matcher and place the normal address binding under that wildcard but add a filter to prevent any * messages other than those of its target address from being routed to it. */ - public static final String ADDRESS_ALLOW_WILDCARD_GROUPINGS = "allow-wildcard-groupings"; + public static final String ALLOW_WILDCARD_GROUPINGS = "allow-wildcard-groupings"; /** * Encodes a {@link Map} of String keys and values that are carried along in the federation policy (address or @@ -388,4 +393,40 @@ public final class AMQPFederationConstants { */ public static final Symbol FEDERATION_POLICY_NAME = Symbol.valueOf("federationPolicyName"); + /** + * Default for configuring a federation address receiver to request that the address resource be auto created on the remote + * if not already in existence. This can allow for multi-hop federation topologies to work in cases where the brokers + * are not configured with static addresses. The default will be to allow auto creation these as has always been done + * prior to adding this configuration option. Users can disable this now which will cause the federation to wait for + * an event indicating the target address has been created and attempt to attach again if local demand is still present. + */ + public static final boolean DEFAULT_ADDRESS_AUTO_CREATE = true; + + /** + * Default for configuring a federation queue receiver to request that the queue resource (and possibly its associated address) + * be auto created on the remote if not already in existence. This can allow for multi-hop federation topologies to work in + * cases where the brokers are not configured with static addresses and queues. The default is to never auto create queues on + * the remote target and instead simply await notification that the remote queue has been created and attempt to attach if + * local demand is still present. + */ + public static final boolean DEFAULT_QUEUE_AUTO_CREATE = false; + + /** + * Default auto deletion setting applied when a federation resource auto creates the queue from which messages are + * federated from on the remote peer. + */ + public static final boolean DEFAULT_AUTO_DELETE = false; + + /** + * Default auto deletion delay setting applied when a federation resource auto creates the queue from which messages are + * federated from on the remote peer. + */ + public static final long DEFAULT_AUTO_DELETE_DELAY = 0L; + + /** + * Default auto deletion message count setting applied when a federation resource auto creates the queue from which messages + * are federated from on the remote peer. + */ + public static final long DEFAULT_AUTO_DELETE_MSG_COUNT = 0L; + } diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupport.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupport.java index 7212cfdd9afc..8d7b3a0a63ee 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupport.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupport.java @@ -17,14 +17,15 @@ package org.apache.activemq.artemis.protocol.amqp.connect.federation; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ENABLE_DIVERT_BINDINGS; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ALLOW_WILDCARD_GROUPINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ENABLE_DIVERT_BINDINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ALLOW_WILDCARD_GROUPINGS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_EXCLUDES; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_INCLUDES; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_MAX_HOPS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.MAX_HOPS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_ADDRESS_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_QUEUE_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.OPERATION_TYPE; @@ -36,6 +37,11 @@ import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.QUEUE_PRIORITY_ADJUSTMENT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.TRANSFORMER_CLASS_NAME; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.TRANSFORMER_PROPERTIES_MAP; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_ADDRESS_AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_QUEUE_AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE_MSG_COUNT; import java.util.AbstractMap; import java.util.AbstractMap.SimpleEntry; @@ -96,10 +102,17 @@ public final class AMQPFederationPolicySupport { /** * Property name used to embed a nested map of properties meant to be applied if the address indicated in an - * federation address receiver auto creates the federated address. + * federation address receiver should be auto created and also the management of the associated durable + * subscription queue for the federation receiver. */ public static final Symbol FEDERATED_ADDRESS_SOURCE_PROPERTIES = Symbol.valueOf("federated-address-source-properties"); + /** + * Property name used to embed a nested map of properties meant to be applied if the queue indicated in an + * federation queue receiver if actions such as auto create should be configured on the queue. + */ + public static final Symbol FEDERATED_QUEUE_SOURCE_PROPERTIES = Symbol.valueOf("federated-queue-source-properties"); + /** * Constructs an address filter for a federated address receiver link that deals with both AMQP messages and * unwrapped Core messages which can carry different hops markers. If the max is less than or equal to zero no filter @@ -139,9 +152,14 @@ public static AMQPMessage encodeQueuePolicyControlMessage(FederationReceiveFromQ annotations.put(OPERATION_TYPE, ADD_QUEUE_POLICY); + policyMap.put(POLICY_NAME, policy.getPolicyName()); policyMap.put(POLICY_NAME, policy.getPolicyName()); policyMap.put(QUEUE_INCLUDE_FEDERATED, policy.isIncludeFederated()); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, policy.getPriorityAjustment()); + policyMap.put(AUTO_CREATE, policy.isAutoCreate()); + policyMap.put(AUTO_DELETE, policy.isAutoDelete()); + policyMap.put(AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); + policyMap.put(AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); if (!policy.getIncludes().isEmpty()) { final List flattenedIncludes = new ArrayList<>(policy.getIncludes().size() * 2); @@ -210,12 +228,13 @@ public static AMQPMessage encodeAddressPolicyControlMessage(FederationReceiveFro annotations.put(OPERATION_TYPE, ADD_ADDRESS_POLICY); policyMap.put(POLICY_NAME, policy.getPolicyName()); - policyMap.put(ADDRESS_AUTO_DELETE, policy.isAutoDelete()); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); - policyMap.put(ADDRESS_MAX_HOPS, policy.getMaxHops()); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, policy.isEnableDivertBindings()); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, policy.isAllowWildcardGroupings()); + policyMap.put(AUTO_CREATE, policy.isAutoCreate()); + policyMap.put(AUTO_DELETE, policy.isAutoDelete()); + policyMap.put(AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); + policyMap.put(AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); + policyMap.put(MAX_HOPS, policy.getMaxHops()); + policyMap.put(ENABLE_DIVERT_BINDINGS, policy.isEnableDivertBindings()); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, policy.isAllowWildcardGroupings()); if (!policy.getIncludes().isEmpty()) { policyMap.put(ADDRESS_INCLUDES, new ArrayList<>(policy.getIncludes())); } @@ -290,6 +309,10 @@ public static FederationReceiveFromQueuePolicy decodeReceiveFromQueuePolicy(AMQP } final String policyName = (String) policyMap.get(POLICY_NAME); + final boolean autoCreate = (Boolean) policyMap.getOrDefault(AUTO_CREATE, DEFAULT_QUEUE_AUTO_CREATE); + final boolean autoDelete = (Boolean) policyMap.getOrDefault(AUTO_DELETE, DEFAULT_AUTO_DELETE); + final long autoDeleteDelay = ((Number) policyMap.getOrDefault(AUTO_DELETE_DELAY, DEFAULT_AUTO_DELETE_DELAY)).longValue(); + final long autoDeleteMsgCount = ((Number) policyMap.getOrDefault(AUTO_DELETE_MSG_COUNT, DEFAULT_AUTO_DELETE_MSG_COUNT)).longValue(); final boolean includeFederated = (boolean) policyMap.getOrDefault(QUEUE_INCLUDE_FEDERATED, false); final int priorityAdjustment = ((Number) policyMap.getOrDefault(QUEUE_PRIORITY_ADJUSTMENT, DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT)).intValue(); final Set> includes = decodeFlattenedFilterSet(policyMap, QUEUE_INCLUDES); @@ -312,7 +335,8 @@ public static FederationReceiveFromQueuePolicy decodeReceiveFromQueuePolicy(AMQP properties = null; } - return new FederationReceiveFromQueuePolicy(policyName, includeFederated, priorityAdjustment, + return new FederationReceiveFromQueuePolicy(policyName, autoCreate, autoDelete, autoDeleteDelay, + autoDeleteMsgCount, includeFederated, priorityAdjustment, includes, excludes, properties, transformerConfig, wildcardConfig); } catch (ActiveMQException amqEx) { @@ -403,18 +427,19 @@ public static FederationReceiveFromAddressPolicy decodeReceiveFromAddressPolicy( "Message body did not carry the required policy name"); } - if (!policyMap.containsKey(ADDRESS_MAX_HOPS)) { + if (!policyMap.containsKey(MAX_HOPS)) { throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.malformedFederationControlMessage( "Message body did not carry the required max hops configuration"); } final String policyName = (String) policyMap.get(POLICY_NAME); - final boolean autoDelete = (Boolean) policyMap.getOrDefault(ADDRESS_AUTO_DELETE, false); - final long autoDeleteDelay = ((Number) policyMap.getOrDefault(ADDRESS_AUTO_DELETE_DELAY, 0L)).longValue(); - final long autoDeleteMsgCount = ((Number) policyMap.getOrDefault(ADDRESS_AUTO_DELETE_MSG_COUNT, 0L)).longValue(); - final int maxHops = ((Number) policyMap.get(ADDRESS_MAX_HOPS)).intValue(); - final boolean enableDiverts = (Boolean) policyMap.getOrDefault(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - final boolean allowWildcardGroupings = (Boolean) policyMap.getOrDefault(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + final boolean autoCreate = (Boolean) policyMap.getOrDefault(AUTO_CREATE, DEFAULT_ADDRESS_AUTO_CREATE); + final boolean autoDelete = (Boolean) policyMap.getOrDefault(AUTO_DELETE, DEFAULT_AUTO_DELETE); + final long autoDeleteDelay = ((Number) policyMap.getOrDefault(AUTO_DELETE_DELAY, DEFAULT_AUTO_DELETE_DELAY)).longValue(); + final long autoDeleteMsgCount = ((Number) policyMap.getOrDefault(AUTO_DELETE_MSG_COUNT, DEFAULT_AUTO_DELETE_MSG_COUNT)).longValue(); + final int maxHops = ((Number) policyMap.get(MAX_HOPS)).intValue(); + final boolean enableDiverts = (Boolean) policyMap.getOrDefault(ENABLE_DIVERT_BINDINGS, false); + final boolean allowWildcardGroupings = (Boolean) policyMap.getOrDefault(ALLOW_WILDCARD_GROUPINGS, false); final Set includes; final Set excludes; @@ -449,7 +474,7 @@ public static FederationReceiveFromAddressPolicy decodeReceiveFromAddressPolicy( properties = null; } - return new FederationReceiveFromAddressPolicy(policyName, autoDelete, autoDeleteDelay, + return new FederationReceiveFromAddressPolicy(policyName, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMsgCount, maxHops, enableDiverts, allowWildcardGroupings, includes, excludes, properties, transformerConfig, wildcardConfig); @@ -495,9 +520,10 @@ public static FederationReceiveFromAddressPolicy create(AMQPFederationAddressPol final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy( element.getName(), - Objects.requireNonNullElse(element.getAutoDelete(), false), - Objects.requireNonNullElse(element.getAutoDeleteDelay(), 0L), - Objects.requireNonNullElse(element.getAutoDeleteMessageCount(), 0L), + Objects.requireNonNullElse(element.getAutoCreate(), DEFAULT_ADDRESS_AUTO_CREATE), + Objects.requireNonNullElse(element.getAutoDelete(), DEFAULT_AUTO_DELETE), + Objects.requireNonNullElse(element.getAutoDeleteDelay(), DEFAULT_AUTO_DELETE_DELAY), + Objects.requireNonNullElse(element.getAutoDeleteMessageCount(), DEFAULT_AUTO_DELETE_MSG_COUNT), element.getMaxHops(), Objects.requireNonNullElse(element.isEnableDivertBindings(), false), Objects.requireNonNullElse(element.isAllowWildcardGroupings(), false), @@ -550,6 +576,10 @@ public static FederationReceiveFromQueuePolicy create(AMQPFederationQueuePolicyE final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy( element.getName(), + Objects.requireNonNullElse(element.getAutoCreate(), DEFAULT_QUEUE_AUTO_CREATE), + Objects.requireNonNullElse(element.getAutoDelete(), DEFAULT_AUTO_DELETE), + Objects.requireNonNullElse(element.getAutoDeleteDelay(), DEFAULT_AUTO_DELETE_DELAY), + Objects.requireNonNullElse(element.getAutoDeleteMessageCount(), DEFAULT_AUTO_DELETE_MSG_COUNT), element.isIncludeFederated(), Objects.requireNonNullElse(element.getPriorityAdjustment(), DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT), includes, diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueConsumer.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueConsumer.java index 3f796de9c9e0..668234fe4384 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueConsumer.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueConsumer.java @@ -17,9 +17,14 @@ package org.apache.activemq.artemis.protocol.amqp.connect.federation; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_POLICY_NAME; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_QUEUE_RECEIVER; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_RECEIVER_PRIORITY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationPolicySupport.FEDERATED_QUEUE_SOURCE_PROPERTIES; import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.AMQP_LINK_INITIALIZER_KEY; import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.verifyDesiredCapability; @@ -127,9 +132,16 @@ protected void doCreateReceiver() { target.setAddress(consumerInfo.getTargetFqqn()); + final Map queueSourceProperties = new HashMap<>(); + queueSourceProperties.put(AUTO_CREATE, policy.isAutoCreate()); + queueSourceProperties.put(AUTO_DELETE, policy.isAutoDelete()); + queueSourceProperties.put(AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); + queueSourceProperties.put(AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); + final Map receiverProperties = new HashMap<>(); receiverProperties.put(FEDERATION_RECEIVER_PRIORITY, consumerInfo.getPriority()); receiverProperties.put(FEDERATION_POLICY_NAME, policy.getPolicyName()); + receiverProperties.put(FEDERATED_QUEUE_SOURCE_PROPERTIES, queueSourceProperties); protonReceiver.setSenderSettleMode(SenderSettleMode.UNSETTLED); protonReceiver.setReceiverSettleMode(ReceiverSettleMode.FIRST); diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueSenderController.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueSenderController.java index 12d16463c4d9..eaa9293dbf31 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueSenderController.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationQueueSenderController.java @@ -17,12 +17,24 @@ package org.apache.activemq.artemis.protocol.amqp.connect.federation; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_QUEUE_RECEIVER; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_QUEUE_AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.DEFAULT_AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationPolicySupport.FEDERATED_QUEUE_SOURCE_PROPERTIES; +import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; +import org.apache.activemq.artemis.api.core.QueueConfiguration; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.server.QueueQueryResult; @@ -76,6 +88,20 @@ public ServerConsumer createServerConsumer(ProtonServerSenderContext senderConte // indicated it was desired, however unless offered by the remote we cannot use it. sender.setDesiredCapabilities(new Symbol[] {AmqpSupport.CORE_MESSAGE_TUNNELING_SUPPORT}); + final Map queueSourceProperties; + + if (sender.getRemoteProperties() == null) { + queueSourceProperties = Collections.emptyMap(); + } else { + queueSourceProperties = (Map) + Objects.requireNonNullElse(sender.getRemoteProperties().get(FEDERATED_QUEUE_SOURCE_PROPERTIES), Collections.emptyMap()); + } + + final boolean autoCreate = (boolean) queueSourceProperties.getOrDefault(AUTO_CREATE, DEFAULT_QUEUE_AUTO_CREATE); + final boolean autoDelete = (boolean) queueSourceProperties.getOrDefault(AUTO_DELETE, DEFAULT_AUTO_DELETE); + final long autoDeleteDelay = ((Number) queueSourceProperties.getOrDefault(AUTO_DELETE_DELAY, DEFAULT_AUTO_DELETE_DELAY)).longValue(); + final long autoDeleteMsgCount = ((Number) queueSourceProperties.getOrDefault(AUTO_DELETE_MSG_COUNT, DEFAULT_AUTO_DELETE_MSG_COUNT)).longValue(); + final RoutingType routingType = getRoutingType(source); final SimpleString targetAddress; final SimpleString targetQueue; @@ -88,13 +114,39 @@ public ServerConsumer createServerConsumer(ProtonServerSenderContext senderConte targetQueue = SimpleString.of(source.getAddress()); } - final QueueQueryResult result = sessionSPI.queueQuery(targetQueue, routingType, false, null); - if (!result.isExists()) { - federation.registerMissingQueue(targetQueue.toString()); - throw new ActiveMQAMQPNotFoundException("Queue: '" + targetQueue + "' does not exist"); + QueueQueryResult queueQuery = sessionSPI.queueQuery(targetQueue, routingType, false, null); + + if (!queueQuery.isExists()) { + if (autoCreate) { + final QueueConfiguration configuration = QueueConfiguration.of(targetQueue); + + configuration.setAddress(targetAddress); + configuration.setRoutingType(routingType); + configuration.setAutoCreateAddress(true); + configuration.setMaxConsumers(-1); + configuration.setPurgeOnNoConsumers(false); + configuration.setDurable(true); + configuration.setAutoDelete(autoDelete); + configuration.setAutoDeleteDelay(autoDeleteDelay); + configuration.setAutoDeleteMessageCount(autoDeleteMsgCount); + + // Try and create it and then later we will validate fully that it matches our expectations + // since we could lose a race with some other resource creating its own resources. + queueQuery = sessionSPI.queueQuery(configuration, true); + + // It still might not create based on broker settings and user roles so in that case + // we setup a watcher to send an event if it ever does come into existence. + if (!queueQuery.isExists()) { + federation.registerMissingQueue(targetQueue.toString()); + throw new ActiveMQAMQPNotFoundException("Queue: '" + targetQueue + "' does not exist"); + } + } else { + federation.registerMissingQueue(targetQueue.toString()); + throw new ActiveMQAMQPNotFoundException("Queue: '" + targetQueue + "' does not exist"); + } } - if (targetAddress != null && !result.getAddress().equals(targetAddress)) { + if (targetAddress != null && !queueQuery.getAddress().equals(targetAddress)) { federation.registerMissingQueue(targetQueue.toString()); throw new ActiveMQAMQPNotFoundException("Queue: '" + targetQueue + "' is not mapped to specified address: " + targetAddress); } @@ -113,7 +165,7 @@ public ServerConsumer createServerConsumer(ProtonServerSenderContext senderConte } // No need to apply another filter if the current one on the Queue already matches that. - if (result.getFilterString() == null || !filterString.equals(result.getFilterString().toString())) { + if (queueQuery.getFilterString() == null || !filterString.equals(queueQuery.getFilterString().toString())) { selector = filterString; } else { selector = null; diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromAddressPolicy.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromAddressPolicy.java index 9c69395d6808..938e2ef4ae26 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromAddressPolicy.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromAddressPolicy.java @@ -47,6 +47,7 @@ public class FederationReceiveFromAddressPolicy implements FederationReceiveFrom private final Collection excludes; private final String policyName; + private final boolean autoCreate; private final boolean autoDelete; private final long autoDeleteDelay; private final long autoDeleteMessageCount; @@ -56,8 +57,8 @@ public class FederationReceiveFromAddressPolicy implements FederationReceiveFrom private final Map properties; private final TransformerConfiguration transformerConfig; - public FederationReceiveFromAddressPolicy(String name, boolean autoDelete, long autoDeleteDelay, long autoDeleteMessageCount, - int maxHops, boolean enableDivertBindings, boolean allowWildcardGroupings, + public FederationReceiveFromAddressPolicy(String name, boolean autoCreate, boolean autoDelete, long autoDeleteDelay, + long autoDeleteMessageCount, int maxHops, boolean enableDivertBindings, boolean allowWildcardGroupings, Collection includeAddresses, Collection excludeAddresses, Map properties, TransformerConfiguration transformerConfig, WildcardConfiguration wildcardConfig) { @@ -65,6 +66,7 @@ public FederationReceiveFromAddressPolicy(String name, boolean autoDelete, long Objects.requireNonNull(wildcardConfig, "The provided wild card configuration cannot be null"); this.policyName = name; + this.autoCreate = autoCreate; this.autoDelete = autoDelete; this.autoDeleteDelay = autoDeleteDelay; this.autoDeleteMessageCount = autoDeleteMessageCount; @@ -96,6 +98,10 @@ public String getPolicyName() { return policyName; } + public boolean isAutoCreate() { + return autoCreate; + } + public boolean isAutoDelete() { return autoDelete; } diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromQueuePolicy.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromQueuePolicy.java index e0b8d7f807d2..21e855b211d3 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromQueuePolicy.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/federation/FederationReceiveFromQueuePolicy.java @@ -44,12 +44,18 @@ public class FederationReceiveFromQueuePolicy implements FederationReceiveFromRe private final Collection> excludes; private final String policyName; + private final boolean autoCreate; + private final boolean autoDelete; + private final long autoDeleteDelay; + private final long autoDeleteMessageCount; private final boolean includeFederated; private final int priorityAdjustment; private final Map properties; private final TransformerConfiguration transformerConfig; - public FederationReceiveFromQueuePolicy(String name, boolean includeFederated, int priorotyAdjustment, + public FederationReceiveFromQueuePolicy(String name, boolean autoCreate, boolean autoDelete, + long autoDeleteDelay, long autoDeleteMessageCount, + boolean includeFederated, int priorotyAdjustment, Collection> includeQueues, Collection> excludeQueues, Map properties, TransformerConfiguration transformerConfig, @@ -58,6 +64,10 @@ public FederationReceiveFromQueuePolicy(String name, boolean includeFederated, i Objects.requireNonNull(wildcardConfig, "The provided wild card configuration cannot be null"); this.policyName = name; + this.autoCreate = autoCreate; + this.autoDelete = autoDelete; + this.autoDeleteDelay = autoDeleteDelay; + this.autoDeleteMessageCount = autoDeleteMessageCount; this.includeFederated = includeFederated; this.priorityAdjustment = priorotyAdjustment; this.transformerConfig = transformerConfig; @@ -85,6 +95,22 @@ public String getPolicyName() { return policyName; } + public boolean isAutoCreate() { + return autoCreate; + } + + public boolean isAutoDelete() { + return autoDelete; + } + + public long getAutoDeleteDelay() { + return autoDeleteDelay; + } + + public long getAutoDeleteMessageCount() { + return autoDeleteMessageCount; + } + public boolean isIncludeFederated() { return includeFederated; } diff --git a/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupportTest.java b/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupportTest.java index 91e13b82bd56..b02ddeabf5e2 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupportTest.java +++ b/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/connect/federation/AMQPFederationPolicySupportTest.java @@ -53,14 +53,15 @@ import org.junit.jupiter.api.Test; import static org.apache.activemq.artemis.core.config.WildcardConfiguration.DEFAULT_WILDCARD_CONFIGURATION; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ENABLE_DIVERT_BINDINGS; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ALLOW_WILDCARD_GROUPINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ENABLE_DIVERT_BINDINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ALLOW_WILDCARD_GROUPINGS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_EXCLUDES; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_INCLUDES; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_MAX_HOPS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.MAX_HOPS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_ADDRESS_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_QUEUE_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.OPERATION_TYPE; @@ -97,12 +98,12 @@ public void testEncodeReceiveFromQueuePolicy() { properties2.put("amqpCredits", 10); properties2.put("amqpLowCredits", 3); - doTestEncodeReceiveFromQueuePolicy("test", false, 0, includes, excludes, properties1); - doTestEncodeReceiveFromQueuePolicy("test", true, 5, includes, excludes, properties2); - doTestEncodeReceiveFromQueuePolicy("test", false, -5, includes, excludes, null); - doTestEncodeReceiveFromQueuePolicy("test", true, 5, null, excludes, properties2); - doTestEncodeReceiveFromQueuePolicy("test", true, 5, includes, null, properties2); - doTestEncodeReceiveFromQueuePolicy("test", true, 5, Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()); + doTestEncodeReceiveFromQueuePolicy("test", false, false, 0, 1, false, 0, includes, excludes, properties1); + doTestEncodeReceiveFromQueuePolicy("test", false, true, 1, 1, true, 5, includes, excludes, properties2); + doTestEncodeReceiveFromQueuePolicy("test", true, false, 2, 1, false, -5, includes, excludes, null); + doTestEncodeReceiveFromQueuePolicy("test", true, true, 3, 2, true, 5, null, excludes, properties2); + doTestEncodeReceiveFromQueuePolicy("test", false, true, 10, 5, true, 5, includes, null, properties2); + doTestEncodeReceiveFromQueuePolicy("test", true, false, 0, 0, true, 5, Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()); } @Test @@ -111,7 +112,7 @@ public void testEncodeReceiveFromQueuePolicyNoExcludes() { includes.add(new SimpleEntry<>("a", "b")); includes.add(new SimpleEntry<>("c", "d")); - doTestEncodeReceiveFromQueuePolicy("includes", false, 0, includes, null, null); + doTestEncodeReceiveFromQueuePolicy("includes", false, false, 0, 1, false, 0, includes, null, null); } @Test @@ -120,7 +121,7 @@ public void testEncodeReceiveFromQueuePolicyNoIncludes() { excludes.add(new SimpleEntry<>("e", "f")); excludes.add(new SimpleEntry<>("g", "h")); - doTestEncodeReceiveFromQueuePolicy("excludes", false, 0, null, excludes, null); + doTestEncodeReceiveFromQueuePolicy("excludes", true, true, 1, 2, false, 0, null, excludes, null); } @Test @@ -132,17 +133,20 @@ public void testEncodeReceiveFromQueuePolicyNullsAndEmptyStrings() { excludes.add(new SimpleEntry<>("e", "")); excludes.add(new SimpleEntry<>("g", null)); - doTestEncodeReceiveFromQueuePolicy("excludes", false, 0, includes, excludes, null); + doTestEncodeReceiveFromQueuePolicy("excludes", true, false, 3, 4, false, 0, includes, excludes, null); } @SuppressWarnings("unchecked") private void doTestEncodeReceiveFromQueuePolicy(String name, + boolean autoCreate, boolean autoDelete, + long autoDeleteDelay, long autoDeleteMessageCount, boolean includeFederated, int priorityAdjustment, Collection> includes, Collection> excludes, Map policyProperties) { final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy( - name, includeFederated, priorityAdjustment, includes, excludes, policyProperties, null, DEFAULT_WILDCARD_CONFIGURATION); + name, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, + includeFederated, priorityAdjustment, includes, excludes, policyProperties, null, DEFAULT_WILDCARD_CONFIGURATION); final AMQPMessage message = AMQPFederationPolicySupport.encodeQueuePolicyControlMessage(policy); @@ -157,6 +161,10 @@ private void doTestEncodeReceiveFromQueuePolicy(String name, assertEquals(name, policyMap.get(POLICY_NAME)); assertEquals(includeFederated, policyMap.get(QUEUE_INCLUDE_FEDERATED)); assertEquals(priorityAdjustment, policyMap.get(QUEUE_PRIORITY_ADJUSTMENT)); + assertEquals(autoCreate, policyMap.get(AUTO_CREATE)); + assertEquals(autoDelete, policyMap.get(AUTO_DELETE)); + assertEquals(autoDeleteDelay, policyMap.get(AUTO_DELETE_DELAY)); + assertEquals(autoDeleteMessageCount, policyMap.get(AUTO_DELETE_MSG_COUNT)); if (includes == null || includes.isEmpty()) { assertFalse(policyMap.containsKey(QUEUE_INCLUDES)); @@ -225,17 +233,18 @@ public void testEncodeReceiveFromAddressPolicy() { properties2.put("amqpCredits", 10); properties2.put("amqpLowCredits", 3); - doTestEncodeReceiveFromAddressPolicy("test", false, 0, 1, 2, true, false, includes, excludes, properties1); - doTestEncodeReceiveFromAddressPolicy("test", true, 1, 3, 2, false, true, includes, excludes, null); - doTestEncodeReceiveFromAddressPolicy("test", false, 2, 4, -1, false, false, includes, excludes, properties2); - doTestEncodeReceiveFromAddressPolicy("test", true, 7, -1, 255, true, true, includes, excludes, null); - doTestEncodeReceiveFromAddressPolicy("test", false, 2, 4, -1, false, true, null, excludes, properties2); - doTestEncodeReceiveFromAddressPolicy("test", true, 7, -1, 255, true, false, includes, null, null); - doTestEncodeReceiveFromAddressPolicy("test", true, 7, -1, 255, true, true, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); + doTestEncodeReceiveFromAddressPolicy("test", true, false, 0, 1, 2, true, false, includes, excludes, properties1); + doTestEncodeReceiveFromAddressPolicy("test", true, true, 1, 3, 2, false, true, includes, excludes, null); + doTestEncodeReceiveFromAddressPolicy("test", false, false, 2, 4, -1, false, false, includes, excludes, properties2); + doTestEncodeReceiveFromAddressPolicy("test", false, true, 7, -1, 255, true, true, includes, excludes, null); + doTestEncodeReceiveFromAddressPolicy("test", false, false, 2, 4, -1, false, true, null, excludes, properties2); + doTestEncodeReceiveFromAddressPolicy("test", true, true, 7, -1, 255, true, false, includes, null, null); + doTestEncodeReceiveFromAddressPolicy("test", false, true, 7, -1, 255, true, true, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); } @SuppressWarnings("unchecked") private void doTestEncodeReceiveFromAddressPolicy(String name, + boolean autoCreate, boolean autoDelete, long autoDeleteDelay, long autoDeleteMessageCount, @@ -246,7 +255,7 @@ private void doTestEncodeReceiveFromAddressPolicy(String name, Collection excludes, Map policyProperties) { final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy( - name, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, enableDivertBindings, + name, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, enableDivertBindings, allowWildcardGroupings, includes, excludes, policyProperties, null, DEFAULT_WILDCARD_CONFIGURATION); final AMQPMessage message = AMQPFederationPolicySupport.encodeAddressPolicyControlMessage(policy); @@ -260,12 +269,13 @@ private void doTestEncodeReceiveFromAddressPolicy(String name, final Map policyMap = (Map) ((AmqpValue) message.getBody()).getValue(); assertEquals(name, policyMap.get(POLICY_NAME)); - assertEquals(autoDelete, policyMap.get(ADDRESS_AUTO_DELETE)); - assertEquals(autoDeleteDelay, policyMap.get(ADDRESS_AUTO_DELETE_DELAY)); - assertEquals(autoDeleteMessageCount, policyMap.get(ADDRESS_AUTO_DELETE_MSG_COUNT)); - assertEquals(maxHops, policyMap.get(ADDRESS_MAX_HOPS)); - assertEquals(enableDivertBindings, policyMap.get(ADDRESS_ENABLE_DIVERT_BINDINGS)); - assertEquals(allowWildcardGroupings, policyMap.get(ADDRESS_ALLOW_WILDCARD_GROUPINGS)); + assertEquals(autoCreate, policyMap.get(AUTO_CREATE)); + assertEquals(autoDelete, policyMap.get(AUTO_DELETE)); + assertEquals(autoDeleteDelay, policyMap.get(AUTO_DELETE_DELAY)); + assertEquals(autoDeleteMessageCount, policyMap.get(AUTO_DELETE_MSG_COUNT)); + assertEquals(maxHops, policyMap.get(MAX_HOPS)); + assertEquals(enableDivertBindings, policyMap.get(ENABLE_DIVERT_BINDINGS)); + assertEquals(allowWildcardGroupings, policyMap.get(ALLOW_WILDCARD_GROUPINGS)); if (includes == null || includes.isEmpty()) { assertFalse(policyMap.containsKey(ADDRESS_INCLUDES)); @@ -321,7 +331,7 @@ public void testDecodeReceiveFromQueuePolicyWithSingleIncludeAndExclude() throws final Set> excludes = new LinkedHashSet<>(); excludes.add(new SimpleEntry<>("c", "d")); - doTestDecodeReceiveFromQueuePolicy("address", "test", false, 0, includes, excludes, null); + doTestDecodeReceiveFromQueuePolicy("address", "test", true, false, 1, 6, false, 0, includes, excludes, null); } @Test @@ -331,7 +341,7 @@ public void testDecodeReceiveFromQueuePolicyWithNullMatches() throws ActiveMQExc final Set> excludes = new LinkedHashSet<>(); excludes.add(new SimpleEntry<>(null, "b")); - doTestDecodeReceiveFromQueuePolicy("address", "test", false, 0, includes, excludes, null); + doTestDecodeReceiveFromQueuePolicy("address", "test", true, false, 1, 6, false, 0, includes, excludes, null); } @Test @@ -346,15 +356,19 @@ public void testDecodeReceiveFromQueuePolicy() throws ActiveMQException { properties.put("amqpCredits", "10"); properties.put("amqpLowCredits", "3"); - doTestDecodeReceiveFromQueuePolicy("address", "test", false, 0, includes, excludes, null); - doTestDecodeReceiveFromQueuePolicy("address", "test", true, -5, includes, excludes, properties); - doTestDecodeReceiveFromQueuePolicy("address", "test", false, 5, includes, excludes, null); - doTestDecodeReceiveFromQueuePolicy("address", "test", true, -5, includes, null, properties); - doTestDecodeReceiveFromQueuePolicy("address", "test", true, -5, null, excludes, properties); - doTestDecodeReceiveFromQueuePolicy("address", "test", true, -5, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); + doTestDecodeReceiveFromQueuePolicy("address", "test", true, false, 1, 6, false, 0, includes, excludes, null); + doTestDecodeReceiveFromQueuePolicy("address", "test", true, true, 2, 5, true, -5, includes, excludes, properties); + doTestDecodeReceiveFromQueuePolicy("address", "test", false, false, 3, 4, false, 5, includes, excludes, null); + doTestDecodeReceiveFromQueuePolicy("address", "test", false, true, 4, 3, true, -5, includes, null, properties); + doTestDecodeReceiveFromQueuePolicy("address", "test", true, false, 5, 2, true, -5, null, excludes, properties); + doTestDecodeReceiveFromQueuePolicy("address", "test", true, false, 6, 1, true, -5, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); } private void doTestDecodeReceiveFromQueuePolicy(String address, String name, + boolean autoCreate, + boolean autoDelete, + long autoDeleteDelay, + long autoDeleteMessageCount, boolean includeFederated, int priorityAdjustment, Collection> includes, @@ -371,6 +385,10 @@ private void doTestDecodeReceiveFromQueuePolicy(String address, String name, annotations.put(OPERATION_TYPE, ADD_QUEUE_POLICY); policyMap.put(POLICY_NAME, name); + policyMap.put(AUTO_CREATE, autoCreate); + policyMap.put(AUTO_DELETE, autoDelete); + policyMap.put(AUTO_DELETE_DELAY, autoDeleteDelay); + policyMap.put(AUTO_DELETE_MSG_COUNT, autoDeleteMessageCount); policyMap.put(QUEUE_INCLUDE_FEDERATED, includeFederated); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, priorityAdjustment); @@ -403,7 +421,8 @@ private void doTestDecodeReceiveFromQueuePolicy(String address, String name, final FederationReceiveFromQueuePolicy policy = AMQPFederationPolicySupport.decodeReceiveFromQueuePolicy(amqpMessage, DEFAULT_WILDCARD_CONFIGURATION); - checkPolicyMatchesExpectations(policy, name, includeFederated, priorityAdjustment, includes, excludes, policyProperties); + checkPolicyMatchesExpectations(policy, name, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, + includeFederated, priorityAdjustment, includes, excludes, policyProperties); } @Test @@ -423,14 +442,15 @@ public void testDecodeReceiveFromAddressPolicy() throws ActiveMQException { properties.put("amqpCredits", "10"); properties.put("amqpLowCredits", "3"); - doTestDecodeReceiveFromAddressPolicy("address", "test", false, 0, 1, 2, true, false, includes, excludes, null); - doTestDecodeReceiveFromAddressPolicy("address", "test", false, 0, 1, 2, true, true, includes, excludes, properties); - doTestDecodeReceiveFromAddressPolicy("address", "test", false, 0, 1, 2, true, true, null, excludes, null); - doTestDecodeReceiveFromAddressPolicy("address", "test", false, 0, 1, 2, true, false, includes, null, properties); - doTestDecodeReceiveFromAddressPolicy("address", "test", false, 0, 1, 2, true, true, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); + doTestDecodeReceiveFromAddressPolicy("address", "test", true, false, 1, 5, 2, true, false, includes, excludes, null); + doTestDecodeReceiveFromAddressPolicy("address", "test", false, false, 2, 4, 2, true, true, includes, excludes, properties); + doTestDecodeReceiveFromAddressPolicy("address", "test", true, false, 3, 3, 2, true, true, null, excludes, null); + doTestDecodeReceiveFromAddressPolicy("address", "test", true, true, 4, 2, 2, true, false, includes, null, properties); + doTestDecodeReceiveFromAddressPolicy("address", "test", false, false, 5, 1, 2, true, true, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); } private void doTestDecodeReceiveFromAddressPolicy(String address, String name, + boolean autoCreate, boolean autoDelete, long autoDeleteDelay, long autoDeleteMessageCount, @@ -452,12 +472,13 @@ private void doTestDecodeReceiveFromAddressPolicy(String address, String name, annotations.put(OPERATION_TYPE, ADD_ADDRESS_POLICY); policyMap.put(POLICY_NAME, name); - policyMap.put(ADDRESS_AUTO_DELETE, autoDelete); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, autoDeleteDelay); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, autoDeleteMessageCount); - policyMap.put(ADDRESS_MAX_HOPS, maxHops); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, enableDivertBindings); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, allowWildcardGroupings); + policyMap.put(AUTO_CREATE, autoCreate); + policyMap.put(AUTO_DELETE, autoDelete); + policyMap.put(AUTO_DELETE_DELAY, autoDeleteDelay); + policyMap.put(AUTO_DELETE_MSG_COUNT, autoDeleteMessageCount); + policyMap.put(MAX_HOPS, maxHops); + policyMap.put(ENABLE_DIVERT_BINDINGS, enableDivertBindings); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, allowWildcardGroupings); if (includes != null && !includes.isEmpty()) { policyMap.put(ADDRESS_INCLUDES, new ArrayList<>(includes)); @@ -474,7 +495,7 @@ private void doTestDecodeReceiveFromAddressPolicy(String address, String name, final FederationReceiveFromAddressPolicy policy = AMQPFederationPolicySupport.decodeReceiveFromAddressPolicy(amqpMessage, DEFAULT_WILDCARD_CONFIGURATION); - checkPolicyMatchesExpectations(policy, name, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, + checkPolicyMatchesExpectations(policy, name, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, enableDivertBindings, allowWildcardGroupings, includes, excludes, policyProperties); } @@ -491,6 +512,10 @@ public void testDecodeOfQueuePolicyWithOddNumberOfIncludes() throws ActiveMQExce annotations.put(OPERATION_TYPE, ADD_ADDRESS_POLICY); policyMap.put(POLICY_NAME, "test"); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, true); + policyMap.put(AUTO_DELETE_DELAY, 10); + policyMap.put(AUTO_DELETE_MSG_COUNT, 110); policyMap.put(QUEUE_INCLUDE_FEDERATED, false); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 0); @@ -499,7 +524,7 @@ public void testDecodeOfQueuePolicyWithOddNumberOfIncludes() throws ActiveMQExce includes.add("b"); includes.add("c"); - policyMap.put(QUEUE_INCLUDE_FEDERATED, includes); + policyMap.put(QUEUE_INCLUDES, includes); final AMQPMessage amqpMessage = encodeFromAMQPTypes(properties, messageAnnotations, sectionBody); @@ -522,15 +547,19 @@ public void testCreateQueuePolicyFromConfigurationElement() throws ActiveMQExcep properties2.put("amqpCredits", 10); properties2.put("amqpLowCredits", 3); - doTestCreateQueuePolicyFromConfigurationElement("test", false, 0, includes, excludes, properties1); - doTestCreateQueuePolicyFromConfigurationElement("test", true, 5, includes, excludes, properties2); - doTestCreateQueuePolicyFromConfigurationElement("test", false, -5, includes, excludes, null); - doTestCreateQueuePolicyFromConfigurationElement("test", true, 5, null, excludes, properties1); - doTestCreateQueuePolicyFromConfigurationElement("test", true, 5, includes, null, properties2); - doTestCreateQueuePolicyFromConfigurationElement("test", false, 5, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); + doTestCreateQueuePolicyFromConfigurationElement("test", true, false, 0, 1, false, 0, includes, excludes, properties1); + doTestCreateQueuePolicyFromConfigurationElement("test", true, true, 1, 1, true, 5, includes, excludes, properties2); + doTestCreateQueuePolicyFromConfigurationElement("test", true, false, 3, 4, false, -5, includes, excludes, null); + doTestCreateQueuePolicyFromConfigurationElement("test", true, false, 0, 0, true, 5, null, excludes, properties1); + doTestCreateQueuePolicyFromConfigurationElement("test", false, true, 0, 1, true, 5, includes, null, properties2); + doTestCreateQueuePolicyFromConfigurationElement("test", false, false, 0, 1, false, 5, Collections.emptyList(), Collections.emptyList(), Collections.emptyMap()); } private void doTestCreateQueuePolicyFromConfigurationElement(String name, + boolean autoCreate, + boolean autoDelete, + long autoDeleteDelay, + long autoDeleteMessageCount, boolean includeFederated, int priorityAdjustment, Collection> includes, @@ -539,6 +568,10 @@ private void doTestCreateQueuePolicyFromConfigurationElement(String name, final AMQPFederationQueuePolicyElement element = new AMQPFederationQueuePolicyElement(); element.setName(name); + element.setAutoCreate(autoCreate); + element.setAutoDelete(autoDelete); + element.setAutoDeleteDelay(autoDeleteDelay); + element.setAutoDeleteMessageCount(autoDeleteMessageCount); element.setPriorityAdjustment(priorityAdjustment); element.setIncludeFederated(includeFederated); element.setProperties(policyProperties); @@ -557,7 +590,8 @@ private void doTestCreateQueuePolicyFromConfigurationElement(String name, final FederationReceiveFromQueuePolicy policy = AMQPFederationPolicySupport.create(element, DEFAULT_WILDCARD_CONFIGURATION); - checkPolicyMatchesExpectations(policy, name, includeFederated, priorityAdjustment, includes, excludes, policyProperties); + checkPolicyMatchesExpectations(policy, name, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, + includeFederated, priorityAdjustment, includes, excludes, policyProperties); } @Test @@ -577,15 +611,16 @@ public void testCreateAddressPolicyFromConfigurationElement() throws ActiveMQExc properties.put("amqpCredits", "10"); properties.put("amqpLowCredits", "3"); - doTestCreateAddressPolicyFromConfigurationElement("test", false, 0, 1, 2, true, false, includes, excludes, null); - doTestCreateAddressPolicyFromConfigurationElement("test", true, 1, 2, 3, true, true, includes, excludes, properties); - doTestCreateAddressPolicyFromConfigurationElement("test", false, 10, 9, 8, false, true, null, excludes, properties); - doTestCreateAddressPolicyFromConfigurationElement("test", true, 1, 1, 1, false, false, includes, null, null); - doTestCreateAddressPolicyFromConfigurationElement("test", false, 7, 1, 1, true, true, null, null, properties); - doTestCreateAddressPolicyFromConfigurationElement("test", false, 7, 1, 1, true, false, Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()); + doTestCreateAddressPolicyFromConfigurationElement("test", true, false, 0, 1, 2, true, false, includes, excludes, null); + doTestCreateAddressPolicyFromConfigurationElement("test", true, true, 1, 2, 3, true, true, includes, excludes, properties); + doTestCreateAddressPolicyFromConfigurationElement("test", false, false, 10, 9, 8, false, true, null, excludes, properties); + doTestCreateAddressPolicyFromConfigurationElement("test", false, true, 1, 1, 1, false, false, includes, null, null); + doTestCreateAddressPolicyFromConfigurationElement("test", false, false, 7, 1, 1, true, true, null, null, properties); + doTestCreateAddressPolicyFromConfigurationElement("test", true, false, 7, 1, 1, true, false, Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()); } private void doTestCreateAddressPolicyFromConfigurationElement(String name, + boolean autoCreate, boolean autoDelete, long autoDeleteDelay, long autoDeleteMessageCount, @@ -599,6 +634,7 @@ private void doTestCreateAddressPolicyFromConfigurationElement(String name, final AMQPFederationAddressPolicyElement element = new AMQPFederationAddressPolicyElement(); element.setName(name); + element.setAutoCreate(autoCreate); element.setAutoDelete(autoDelete); element.setAutoDeleteDelay(autoDeleteDelay); element.setAutoDeleteMessageCount(autoDeleteMessageCount); @@ -617,17 +653,18 @@ private void doTestCreateAddressPolicyFromConfigurationElement(String name, final FederationReceiveFromAddressPolicy policy = AMQPFederationPolicySupport.create(element, DEFAULT_WILDCARD_CONFIGURATION); - checkPolicyMatchesExpectations(policy, name, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, + checkPolicyMatchesExpectations(policy, name, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, enableDivertBindings, allowWildcardGroupings, includes, excludes, policyProperties); } private void checkPolicyMatchesExpectations(FederationReceiveFromAddressPolicy policy, - String name, boolean autoDelete, long autoDeleteDelay, + String name, boolean autoCreate, boolean autoDelete, long autoDeleteDelay, long autoDeleteMessageCount, int maxHops, boolean enableDivertBindings, boolean enableWildcardSubscriptions, Collection includes, Collection excludes, Map policyProperties) { assertEquals(name, policy.getPolicyName()); + assertEquals(autoCreate, policy.isAutoCreate()); assertEquals(autoDelete, policy.isAutoDelete()); assertEquals(autoDeleteDelay, policy.getAutoDeleteDelay()); assertEquals(autoDeleteMessageCount, policy.getAutoDeleteMessageCount()); @@ -660,11 +697,17 @@ private void checkPolicyMatchesExpectations(FederationReceiveFromAddressPolicy p } private void checkPolicyMatchesExpectations(FederationReceiveFromQueuePolicy policy, - String name, boolean includeFederated, int priorityAdjustment, + String name, boolean autoCreate, boolean autoDelete, + long autoDeleteDelay, long autoDeleteMessageCount, + boolean includeFederated, int priorityAdjustment, Collection includes, Collection excludes, Map policyProperties) { assertEquals(name, policy.getPolicyName()); + assertEquals(autoCreate, policy.isAutoCreate()); + assertEquals(autoDelete, policy.isAutoDelete()); + assertEquals(autoDeleteDelay, policy.getAutoDeleteDelay()); + assertEquals(autoDeleteMessageCount, policy.getAutoDeleteMessageCount()); assertEquals(includeFederated, policy.isIncludeFederated()); assertEquals(priorityAdjustment, policy.getPriorityAjustment()); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationAddressPolicyElement.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationAddressPolicyElement.java index 6f3ef9b64cbf..e87d8fd05084 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationAddressPolicyElement.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationAddressPolicyElement.java @@ -34,6 +34,7 @@ public final class AMQPFederationAddressPolicyElement implements Serializable { private final Map properties = new HashMap<>(); private String name; + private Boolean autoCreate; private Boolean autoDelete; private Long autoDeleteDelay; private Long autoDeleteMessageCount; @@ -156,6 +157,15 @@ public AMQPFederationAddressPolicyElement setAutoDelete(Boolean autoDelete) { return this; } + public Boolean getAutoCreate() { + return autoCreate; + } + + public AMQPFederationAddressPolicyElement setAutoCreate(Boolean autoCreate) { + this.autoCreate = autoCreate; + return this; + } + public Boolean isEnableDivertBindings() { return enableDivertBindings; } @@ -196,6 +206,7 @@ public boolean equals(Object obj) { Objects.equals(includes, other.includes) && Objects.equals(excludes, other.excludes) && Objects.equals(properties, other.properties) && + Objects.equals(autoCreate, other.autoCreate) && Objects.equals(autoDelete, other.autoDelete) && Objects.equals(autoDeleteDelay, other.autoDeleteDelay) && Objects.equals(autoDeleteMessageCount, other.autoDeleteMessageCount) && @@ -207,7 +218,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return Objects.hash(name, includes, excludes, properties, autoDelete, autoDeleteDelay, autoDeleteMessageCount, + return Objects.hash(name, includes, excludes, properties, autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, maxHops, enableDivertBindings, allowWildcardGroupings, transformerConfig); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationQueuePolicyElement.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationQueuePolicyElement.java index a35f8e8b702a..7d70a6cad7cc 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationQueuePolicyElement.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/amqpBrokerConnectivity/AMQPFederationQueuePolicyElement.java @@ -34,6 +34,10 @@ public final class AMQPFederationQueuePolicyElement implements Serializable { private final Map properties = new HashMap<>(); private String name; + private Boolean autoCreate; + private Boolean autoDelete; + private Long autoDeleteDelay; + private Long autoDeleteMessageCount; private boolean includeFederated; private Integer priorityAdjustment; private TransformerConfiguration transformerConfig; @@ -116,6 +120,42 @@ public AMQPFederationQueuePolicyElement setProperties(Map proper return this; } + public Long getAutoDeleteMessageCount() { + return autoDeleteMessageCount; + } + + public AMQPFederationQueuePolicyElement setAutoDeleteMessageCount(Long autoDeleteMessageCount) { + this.autoDeleteMessageCount = autoDeleteMessageCount; + return this; + } + + public Long getAutoDeleteDelay() { + return autoDeleteDelay; + } + + public AMQPFederationQueuePolicyElement setAutoDeleteDelay(Long autoDeleteDelay) { + this.autoDeleteDelay = autoDeleteDelay; + return this; + } + + public Boolean getAutoDelete() { + return autoDelete; + } + + public AMQPFederationQueuePolicyElement setAutoDelete(Boolean autoDelete) { + this.autoDelete = autoDelete; + return this; + } + + public Boolean getAutoCreate() { + return autoCreate; + } + + public AMQPFederationQueuePolicyElement setAutoCreate(Boolean autoCreate) { + this.autoCreate = autoCreate; + return this; + } + public boolean isIncludeFederated() { return includeFederated; } @@ -154,6 +194,10 @@ public boolean equals(Object obj) { return includeFederated == other.includeFederated && Objects.equals(name, other.name) && + Objects.equals(autoCreate, other.autoCreate) && + Objects.equals(autoDelete, other.autoDelete) && + Objects.equals(autoDeleteDelay, other.autoDeleteDelay) && + Objects.equals(autoDeleteMessageCount, other.autoDeleteMessageCount) && Objects.equals(includes, other.includes) && Objects.equals(excludes, other.excludes) && Objects.equals(properties, other.properties) && @@ -163,7 +207,9 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return Objects.hash(name, includeFederated, includes, excludes, properties, priorityAdjustment, transformerConfig); + return Objects.hash(name, includeFederated, includes, excludes, properties, + autoCreate, autoDelete, autoDeleteDelay, autoDeleteMessageCount, + priorityAdjustment, transformerConfig); } // We are required to implement a named match type so that we can perform this configuration diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java index b89948b6e498..31c197ef9c6f 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java @@ -2346,6 +2346,8 @@ private AMQPFederationAddressPolicyElement parseAMQPFederatedFromAddressPolicy(E Node item = attributes.item(i); if (item.getNodeName().equals("max-hops")) { config.setMaxHops(MINUS_ONE_OR_GE_ZERO.validate(item.getNodeName(), Integer.parseInt(item.getNodeValue())).intValue()); + } else if (item.getNodeName().equals("auto-create")) { + config.setAutoCreate(Boolean.parseBoolean(item.getNodeValue())); } else if (item.getNodeName().equals("auto-delete")) { config.setAutoDelete(Boolean.parseBoolean(item.getNodeValue())); } else if (item.getNodeName().equals("auto-delete-delay")) { @@ -2392,6 +2394,14 @@ private AMQPFederationQueuePolicyElement parseAMQPFederatedFromQueuePolicy(Eleme Node item = attributes.item(i); if (item.getNodeName().equals("include-federated")) { config.setIncludeFederated(Boolean.parseBoolean(item.getNodeValue())); + } else if (item.getNodeName().equals("auto-create")) { + config.setAutoCreate(Boolean.parseBoolean(item.getNodeValue())); + } else if (item.getNodeName().equals("auto-delete")) { + config.setAutoDelete(Boolean.parseBoolean(item.getNodeValue())); + } else if (item.getNodeName().equals("auto-delete-delay")) { + config.setAutoDeleteDelay(GE_ZERO.validate("auto-delete-delay", Long.parseLong(item.getNodeValue())).longValue()); + } else if (item.getNodeName().equals("auto-delete-message-count")) { + config.setAutoDeleteMessageCount(MINUS_ONE_OR_GE_ZERO.validate("auto-delete-message-count", Long.parseLong(item.getNodeValue())).longValue()); } else if (item.getNodeName().equals("priority-adjustment")) { config.setPriorityAdjustment(Integer.parseInt(item.getNodeValue())); } diff --git a/artemis-server/src/main/resources/schema/artemis-configuration.xsd b/artemis-server/src/main/resources/schema/artemis-configuration.xsd index 8567d5fe764d..c98ca0f30787 100644 --- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd +++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd @@ -2438,6 +2438,10 @@ + + + + @@ -2472,6 +2476,7 @@ + diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationValidationTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationValidationTest.java index 843034869a85..d6c30f00847a 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationValidationTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationValidationTest.java @@ -140,27 +140,35 @@ public void testAMQPConnectParsing() throws Exception { amqpBrokerConnectConfiguration = fc.getAMQPConnection().get(3); assertFalse(amqpBrokerConnectConfiguration.isAutostart()); AMQPFederatedBrokerConnectionElement federationElement = (AMQPFederatedBrokerConnectionElement) amqpBrokerConnectConfiguration.getConnectionElements().get(0); - assertEquals(1, federationElement.getLocalAddressPolicies().size()); - assertEquals(2, federationElement.getLocalQueuePolicies().size()); - assertEquals(1, federationElement.getRemoteAddressPolicies().size()); - assertEquals(1, federationElement.getRemoteQueuePolicies().size()); + assertEquals(2, federationElement.getLocalAddressPolicies().size()); + assertEquals(3, federationElement.getLocalQueuePolicies().size()); + assertEquals(2, federationElement.getRemoteAddressPolicies().size()); + assertEquals(2, federationElement.getRemoteQueuePolicies().size()); assertTrue(federationElement.getProperties().containsKey("amqpCredits")); assertEquals("7", federationElement.getProperties().get("amqpCredits")); assertTrue(federationElement.getProperties().containsKey("amqpLowCredits")); assertEquals("1", federationElement.getProperties().get("amqpLowCredits")); federationElement.getLocalAddressPolicies().forEach(p -> { - assertEquals("lap1", p.getName()); - assertEquals(1, p.getIncludes().size()); - p.getIncludes().forEach(match -> assertEquals("orders", match.getAddressMatch())); - assertEquals(1, p.getExcludes().size()); - p.getExcludes().forEach(match -> assertEquals("all.#", match.getAddressMatch())); - assertFalse(p.getAutoDelete()); - assertEquals(1L, (long) p.getAutoDeleteDelay()); - assertEquals(12L, (long) p.getAutoDeleteMessageCount()); - assertEquals(2, (int) p.getMaxHops()); - assertNotNull(p.getTransformerConfiguration()); - assertEquals("class-name", p.getTransformerConfiguration().getClassName()); + if (p.getName().endsWith("lap1")) { + assertEquals("lap1", p.getName()); + assertEquals(1, p.getIncludes().size()); + p.getIncludes().forEach(match -> assertEquals("orders", match.getAddressMatch())); + assertEquals(1, p.getExcludes().size()); + p.getExcludes().forEach(match -> assertEquals("all.#", match.getAddressMatch())); + assertNull(p.getAutoCreate()); + assertFalse(p.getAutoDelete()); + assertEquals(1L, (long) p.getAutoDeleteDelay()); + assertEquals(12L, (long) p.getAutoDeleteMessageCount()); + assertEquals(2, p.getMaxHops()); + assertNotNull(p.getTransformerConfiguration()); + assertEquals("class-name", p.getTransformerConfiguration().getClassName()); + } else if (p.getName().endsWith("lap2")) { + assertEquals("lap2", p.getName()); + assertFalse(p.getAutoCreate()); + } else { + fail("Should only be two local address policies"); + } }); federationElement.getLocalQueuePolicies().forEach((p) -> { if (p.getName().endsWith("lqp1")) { @@ -171,48 +179,72 @@ public void testAMQPConnectParsing() throws Exception { assertFalse(p.getProperties().isEmpty()); assertTrue(p.getProperties().containsKey("amqpCredits")); assertEquals("1", p.getProperties().get("amqpCredits")); + assertNull(p.getAutoCreate()); } else if (p.getName().endsWith("lqp2")) { assertNull(p.getPriorityAdjustment()); assertFalse(p.isIncludeFederated()); + assertNull(p.getAutoCreate()); + } else if (p.getName().endsWith("lqp3")) { + assertNull(p.getPriorityAdjustment()); + assertFalse(p.isIncludeFederated()); + assertTrue(p.getAutoCreate()); } else { - fail("Should only be two local queue policies"); + fail("Should only be three local queue policies"); } }); federationElement.getRemoteAddressPolicies().forEach((p) -> { - assertEquals("rap1", p.getName()); - assertEquals(1, p.getIncludes().size()); - p.getIncludes().forEach(match -> assertEquals("support", match.getAddressMatch())); - assertEquals(0, p.getExcludes().size()); - assertTrue(p.getAutoDelete()); - assertEquals(2L, (long) p.getAutoDeleteDelay()); - assertEquals(42L, (long) p.getAutoDeleteMessageCount()); - assertEquals(1, (int) p.getMaxHops()); - assertNotNull(p.getTransformerConfiguration()); - assertEquals("something", p.getTransformerConfiguration().getClassName()); - assertEquals(2, p.getTransformerConfiguration().getProperties().size()); - assertEquals("value1", p.getTransformerConfiguration().getProperties().get("key1")); - assertEquals("value2", p.getTransformerConfiguration().getProperties().get("key2")); - assertNotNull(p.getProperties()); - assertFalse(p.getProperties().isEmpty()); - assertTrue(p.getProperties().containsKey("amqpCredits")); - assertEquals("2", p.getProperties().get("amqpCredits")); - assertTrue(p.getProperties().containsKey("amqpLowCredits")); - assertEquals("1", p.getProperties().get("amqpLowCredits")); + if (p.getName().endsWith("rap1")) { + assertEquals("rap1", p.getName()); + assertEquals(1, p.getIncludes().size()); + p.getIncludes().forEach(match -> assertEquals("support", match.getAddressMatch())); + assertEquals(0, p.getExcludes().size()); + assertTrue(p.getAutoDelete()); + assertEquals(2L, (long) p.getAutoDeleteDelay()); + assertEquals(42L, (long) p.getAutoDeleteMessageCount()); + assertEquals(1, p.getMaxHops()); + assertNotNull(p.getTransformerConfiguration()); + assertEquals("something", p.getTransformerConfiguration().getClassName()); + assertEquals(2, p.getTransformerConfiguration().getProperties().size()); + assertEquals("value1", p.getTransformerConfiguration().getProperties().get("key1")); + assertEquals("value2", p.getTransformerConfiguration().getProperties().get("key2")); + assertNotNull(p.getProperties()); + assertFalse(p.getProperties().isEmpty()); + assertTrue(p.getProperties().containsKey("amqpCredits")); + assertEquals("2", p.getProperties().get("amqpCredits")); + assertTrue(p.getProperties().containsKey("amqpLowCredits")); + assertEquals("1", p.getProperties().get("amqpLowCredits")); + } else if (p.getName().endsWith("rap2")) { + assertEquals("rap2", p.getName()); + assertFalse(p.getAutoCreate()); + } else { + fail("Should only be two remote address policies"); + } }); federationElement.getRemoteQueuePolicies().forEach((p) -> { - assertEquals("rqp1", p.getName()); - assertEquals(-1, (int) p.getPriorityAdjustment()); - assertTrue(p.isIncludeFederated()); - p.getIncludes().forEach(match -> { - assertEquals("#", match.getAddressMatch()); - assertEquals("tracking", match.getQueueMatch()); - }); - assertNotNull(p.getProperties()); - assertFalse(p.getProperties().isEmpty()); - assertTrue(p.getProperties().containsKey("amqpCredits")); - assertEquals("2", p.getProperties().get("amqpCredits")); - assertTrue(p.getProperties().containsKey("amqpLowCredits")); - assertEquals("1", p.getProperties().get("amqpLowCredits")); + if (p.getName().endsWith("rqp1")) { + assertEquals("rqp1", p.getName()); + assertEquals(-1, (int) p.getPriorityAdjustment()); + assertTrue(p.isIncludeFederated()); + p.getIncludes().forEach(match -> { + assertEquals("#", match.getAddressMatch()); + assertEquals("tracking", match.getQueueMatch()); + }); + assertNotNull(p.getProperties()); + assertFalse(p.getProperties().isEmpty()); + assertTrue(p.getProperties().containsKey("amqpCredits")); + assertEquals("2", p.getProperties().get("amqpCredits")); + assertTrue(p.getProperties().containsKey("amqpLowCredits")); + assertEquals("1", p.getProperties().get("amqpLowCredits")); + assertNull(p.getAutoCreate()); + } else if (p.getName().endsWith("rqp2")) { + assertEquals("rqp2", p.getName()); + assertTrue(p.getAutoCreate()); + assertTrue(p.getAutoDelete()); + assertEquals(2L, (long) p.getAutoDeleteDelay()); + assertEquals(42L, (long) p.getAutoDeleteMessageCount()); + } else { + fail("Should only be two remote queue policies"); + } }); amqpBrokerConnectConfiguration = fc.getAMQPConnection().get(4); diff --git a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml index ba33b5a739e2..2d279fddb91d 100644 --- a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml +++ b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml @@ -520,6 +520,21 @@ + + + + + + + + + + + + + + + diff --git a/docs/user-manual/amqp-federation-configuration-glossary.adoc b/docs/user-manual/amqp-federation-configuration-glossary.adoc index 9f5be0b09c8f..6fd37634a161 100644 --- a/docs/user-manual/amqp-federation-configuration-glossary.adoc +++ b/docs/user-manual/amqp-federation-configuration-glossary.adoc @@ -80,7 +80,7 @@ In this case the policy is sent across the connection to the remote broker and f ---- -=== Address federation configuration elements +== Address federation configuration elements [,xml] ---- @@ -113,6 +113,10 @@ max-hops:: The maximum number of hops that a message can perform to be federated. Default value is `0` and will work for most federation deployments. However, in certain topologies where a loop is configured a higher value may be required to prevent infinite looping of messages. +auto-create:: +Controls if the federation receiver will attempt to create the target address if it does not exist on the remote when it attaches. +By default federation receivers will attempt to auto create the target address when they attach so that they do not miss any messages later when a producer starts sending messages to that address. +The configuration can be set to 'false' to indicate that if the remote address does not exist no address create attempt is made and the federation framework will send an event to the source when the address is created on the target. auto-delete:: For address federation, a durable queue is created on the broker from which messages are being federated. Set this property to `true` to mark the queue for automatic deletion once the initiating broker disconnects and the delay and message count parameters are met. @@ -144,7 +148,7 @@ The address-match pattern to use to match excluded addresses, multiple of these property:: A key / value property setting that allows for configuration options to be set either at the root federation level or within each federation policy that affects some defined behavior of the policy implementation. -=== Queue federation configuration elements +== Queue federation configuration elements [,xml] ---- @@ -172,6 +176,21 @@ When federation consumers are created this value can be used to ensure that thos The default is `-1`. include-federated:: Controls if consumers on a queue which come from federation instances should be counted when observing a queue for demand, by default this value is `false` and federation consumers are not counted as local demand. +auto-create:: +Controls if the federation receiver will attempt to create the target queue (and possibly its associated address) if it does not exist on the remote when it attaches. +By default federation queue receivers will not attempt to auto create the target queue when they attach and the queue does not exist on the target and will simply listen for an event from the target indicating that the desired queue has now come into existence and to try again. +The configuration can be set to 'true' to indicate that if the remote queue does not exist an attempt to create it should be made by the federation framework, this is useful for some configurations such as multi-hop queue federations where the intermediate peer does not define all the queues statically. +auto-delete:: +For queue federation, if a durable queue is created on the broker by the federation framework that queue can be configured for auto deletion later. +Set this property to `true` to mark the queue for automatic deletion once the initiating broker disconnects and the delay and message count parameters are met. +This can is a useful option if you want to automate the cleanup of dynamically-created queues. +The default value is `false`, which means that the queue is not automatically deleted. +auto-delete-delay:: +The amount of time in milliseconds after the initiating broker has disconnected before the created queue can be eligible for `auto-delete`. +The default value is `0` when option is omitted. +auto-delete-message-count:: +After the initiating broker has disconnected, the maximum number of messages allowed in the remote queue for the queue to be eligible for automatic deletion. +The default value is `0`. The following set of elements can be configured within the queue policy to control the behavior of the deployed policy. @@ -184,7 +203,7 @@ Multiple of these can be set, or it can be omitted if no excludes are needed. property:: A key / value property setting that allows for configuration options to be set either at the root federation level or within each federation policy that affects some defined behavior of the policy implementation. -=== Federation policy property configuration index +== Federation policy property configuration index The following properties can be set either at the federation element level or set per-policy in order to apply different behaviors to different policies within the same federation configuration. When remote address or queue policies are configured the value of these properties are sent to the remote along with the policies to ensure both sides are operating with the same configurations. diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationAddressPolicyTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationAddressPolicyTest.java index 1cd0c1fefdb7..693365a988c1 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationAddressPolicyTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationAddressPolicyTest.java @@ -18,14 +18,15 @@ package org.apache.activemq.artemis.tests.integration.amqp.connect; import static org.apache.activemq.artemis.core.config.WildcardConfiguration.DEFAULT_WILDCARD_CONFIGURATION; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ENABLE_DIVERT_BINDINGS; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ALLOW_WILDCARD_GROUPINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ENABLE_DIVERT_BINDINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ALLOW_WILDCARD_GROUPINGS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_EXCLUDES; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_INCLUDES; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_MAX_HOPS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.MAX_HOPS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_RECEIVER_IDLE_TIMEOUT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_ADDRESS_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.EVENT_TYPE; @@ -229,9 +230,10 @@ public void testFederationCreatesAddressReceiverWhenLocalQueueIsStaticlyDefined( peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.expectAttach().ofReceiver() .withDesiredCapability(FEDERATION_ADDRESS_RECEIVER.toString()) @@ -333,9 +335,10 @@ public void testFederationCreatesReceiverWithoutFQQNWhenLocalQueueIsStaticlyDefi peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.expectAttach().ofReceiver() .withDesiredCapability(FEDERATION_ADDRESS_RECEIVER.toString()) @@ -413,9 +416,10 @@ public void testFederationCreatesReceiverWithStableFQQNWhenLocalDemandIsAppliedR peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); final AtomicReference capturedSourceAddress1 = new AtomicReference<>(); final AtomicReference capturedSourceAddress2 = new AtomicReference<>(); @@ -670,9 +674,10 @@ public void testFederationCreatesAddressReceiverLinkForAddressMatch() throws Exc server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -746,9 +751,10 @@ public void testFederationCreatesAddressReceiverLinkForAddressMatchUsingPolicyCr server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -847,9 +853,10 @@ private void doTestFederationCreatesAddressReceiverLinkForAddressWithCorrectFilt selectors.put(AmqpSupport.NO_LOCAL_NAME.toString(), new AmqpNoLocalFilter()); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); final AtomicReference capturedAttach = new AtomicReference<>(); @@ -996,9 +1003,10 @@ public void doTestFederationClosesAddressReceiverLinkWhenDemandRemoved(int idleT server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -1080,9 +1088,10 @@ public void testFederationRetainsAddressReceiverLinkWhenDurableSubscriberIsOffli server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -1171,9 +1180,10 @@ public void testFederationClosesAddressReceiverLinkWaitsForAllDemandToRemoved() server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -1353,9 +1363,10 @@ public void testFederationConsumerCreatedWhenDemandAddedToDivertAddress() throws server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the forwarding address should create a remote consumer for the forwarded address. peer.waitForScriptToComplete(5, TimeUnit.SECONDS); @@ -1440,9 +1451,10 @@ public void testFederationConsumerCreatedWhenDemandAddedToCompositeDivertAddress server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the forwarding address should create a remote consumer for the forwarded address. peer.waitForScriptToComplete(5, TimeUnit.SECONDS); @@ -1535,9 +1547,10 @@ public void testFederationConsumerRemovesDemandFromDivertConsumersOnlyWhenAllDem server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the forwarding address should create a remote consumer for the forwarded address. peer.waitForScriptToComplete(5, TimeUnit.SECONDS); @@ -1628,9 +1641,10 @@ public void testFederationConsumerRetainsDemandForDivertBindingWithoutActiveAnyc server.addAddressInfo(new AddressInfo(SimpleString.of("source"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the forwarding address should create a remote consumer for the forwarded address. peer.waitForScriptToComplete(5, TimeUnit.SECONDS); @@ -1719,9 +1733,10 @@ public void testFederationConsumerRemovesDemandForDivertBindingWithoutActiveMult server.addAddressInfo(new AddressInfo(SimpleString.of("source"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the forwarding address should create a remote consumer for the forwarded address. peer.waitForScriptToComplete(5, TimeUnit.SECONDS); @@ -1810,9 +1825,10 @@ public void testFederationRemovesRemoteDemandIfDivertIsRemoved() throws Exceptio server.addAddressInfo(new AddressInfo(SimpleString.of("source"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the forwarding address should create a remote consumer for the forwarding address. peer.waitForScriptToComplete(5, TimeUnit.SECONDS); @@ -1897,9 +1913,10 @@ public void testDivertBindingsDoNotCreateAdditionalDemandIfDemandOnForwardingAdd server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Demand on the main address creates demand on the same address remotely and then the diverts // should just be tracked under that original demand. @@ -2037,7 +2054,7 @@ public void testRemoteBrokerAcceptsAddressPolicyFromControlLink() throws Excepti final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, excludes, null, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -2083,7 +2100,7 @@ public void testRemoteBrokerAcceptsAddressPolicyFromControlLinkWithTransformerCo final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, excludes, null, transformerConfiguration, DEFAULT_WILDCARD_CONFIGURATION); @@ -2121,7 +2138,7 @@ public void testRemoteFederatesAddressWhenDemandIsApplied() throws Exception { final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -2191,7 +2208,7 @@ public void testRemoteFederatesAddressWhenDemandIsAppliedUsingFQQNWhenSupported( final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -2263,7 +2280,7 @@ public void testRemoteFederatesAddressWhenDemandIsAppliedUsingControllerDefinedL final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -2337,7 +2354,7 @@ public void testRemoteFederatesAddressWhenDemandIsAppliedUsingPolicyDefinedLinkC final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -2416,7 +2433,7 @@ public void testRemoteFederatesAddressAndAppliesTransformerWhenDemandIsApplied() final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, null, properties, transformerConfiguration, DEFAULT_WILDCARD_CONFIGURATION); @@ -2481,9 +2498,9 @@ public void testRemoteBrokerAnswersAttachOfFederationReceiverProperly() throws E server.start(); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test"); @@ -3528,12 +3545,13 @@ public void testFederationCreatesEventSenderAndReceiverWhenLocalAndRemotePolicie includes.add("test"); policyMap.put(POLICY_NAME, "remote-address-policy"); - policyMap.put(ADDRESS_AUTO_DELETE, false); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); - policyMap.put(ADDRESS_MAX_HOPS, 5); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + policyMap.put(AUTO_CREATE, true); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, -1L); + policyMap.put(AUTO_DELETE_MSG_COUNT, -1L); + policyMap.put(MAX_HOPS, 5); + policyMap.put(ENABLE_DIVERT_BINDINGS, false); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, false); policyMap.put(ADDRESS_INCLUDES, includes); final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(policyMap); @@ -3615,12 +3633,13 @@ public void testFederationSendsRemotePolicyIfEventsSenderLinkRejected() throws E includes.add("test"); policyMap.put(POLICY_NAME, "remote-address-policy"); - policyMap.put(ADDRESS_AUTO_DELETE, false); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); - policyMap.put(ADDRESS_MAX_HOPS, 5); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + policyMap.put(AUTO_CREATE, true); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, -1L); + policyMap.put(AUTO_DELETE_MSG_COUNT, -1L); + policyMap.put(MAX_HOPS, 5); + policyMap.put(ENABLE_DIVERT_BINDINGS, false); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, false); policyMap.put(ADDRESS_INCLUDES, includes); final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(policyMap); @@ -3686,9 +3705,9 @@ public void testRemoteBrokerSendsAddressAddedEventForInterestedPeer() throws Exc server.start(); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); final MessageAnnotationsMatcher maMatcher = new MessageAnnotationsMatcher(true); maMatcher.withEntry(EVENT_TYPE.toString(), Matchers.is(REQUESTED_ADDRESS_ADDED)); @@ -3795,9 +3814,10 @@ public void testFederationCreatesAddressReceiverInResponseToAddressAddedEvent() peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); // Reject the initial attempt peer.expectAttach().ofReceiver() @@ -4205,7 +4225,7 @@ public void testBrokerAllowsAttachToPreviouslyNonExistentAddressAfterItIsAdded() server.start(); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE, false); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test"); @@ -4317,9 +4337,10 @@ public void testAddressPolicyCanOverridesZeroCreditsInFederationConfigurationAnd server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -4353,9 +4374,9 @@ public void testRemoteFederationReceiverCloseWhenDemandRemovedDoesNotTerminateRe server.start(); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 1_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 1_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test"); @@ -4440,9 +4461,9 @@ public void testRemoteFederationReceiverCloseWithErrorTerminateRemoteConnection( server.start(); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 1_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 1_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test"); @@ -4509,9 +4530,9 @@ public void testRemoteReceiverClosedWhenDemandRemovedCleansUpAddressBinding() th server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, false); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 1_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + remoteSourceProperties.put(AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 1_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test"); @@ -4588,9 +4609,9 @@ public void testRemoteReceiverClosedWhenDemandRemovedCleansUpAddressBindingWhenU server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, false); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 1_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + remoteSourceProperties.put(AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 1_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test", true); @@ -4667,7 +4688,7 @@ public void testRemoteConnectionSuddenDropLeaveAddressBindingIntact() throws Exc server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE, false); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test"); @@ -4812,13 +4833,13 @@ private void doTestFederationAddressBindingAppliesAutoDeletePolicyToCreatedQueue final Map remoteSourceProperties = new HashMap<>(); if (autoDelete) { - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 200L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 200L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); } else { - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, false); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + remoteSourceProperties.put(AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE_DELAY, -1L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); } try (ProtonTestClient peer = new ProtonTestClient()) { @@ -5647,9 +5668,10 @@ public void testFederationCreatesFilteredAddressReceiversWhenLocalQueuesAreStati peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); final String expectedJMSFilter1 = "color='red'"; final String expectedJMSFilter2 = "color='blue'"; @@ -5815,9 +5837,10 @@ public void testFederationCreatesFilteredAddressReceiversWhenConsumerAddedAndRou peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); final String expectedJMSFilter = "color='red'"; final AtomicReference capturedAttach = new AtomicReference<>(); @@ -6022,9 +6045,10 @@ public void testFederationCreatesSingleUnfilteredConsumerWhenRemoteDoesNotSuppor peer.waitForScriptToComplete(5, TimeUnit.SECONDS); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, false); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); final String jmsFilterQueue1 = "color='red'"; final String jmsFilterQueue2 = "color='blue'"; @@ -6488,9 +6512,9 @@ public void testRemoteReFederatesAddressWhenDemandIsAppliedAfterInitialDeliveryM server.start(); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 100_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 100_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test", true); @@ -6709,7 +6733,7 @@ private void testRemoteFederationRespectsUseModifiedForRejectConfiguration(boole final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, -1, true, false, + true, true, 30_000L, 1000L, -1, true, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -6910,9 +6934,9 @@ public void testFederationSourceDoesNotTreatTargetFilteredFederationReceiversAsL private void doTestFederationSourceDoesNotTreatTargetFederationReceiversAsLocalDemand(boolean includeFilterId) throws Exception { final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 100_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 100_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); final String remoteNodeID = UUID.randomUUID().toString(); final String federationBindingName; @@ -7067,7 +7091,7 @@ public void testRemoteFederationDoesNotCreateLinksForAddressItCannotWriteTo() th final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, false, false, + true, true, 30_000L, 1000L, 1, false, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -7173,7 +7197,7 @@ public void testRemoteFederationDoesNotCreateLinksForAddressItCannotWriteToThatH final FederationReceiveFromAddressPolicy policy = new FederationReceiveFromAddressPolicy("test-address-policy", - true, 30_000L, 1000L, 1, true, false, + true, true, 30_000L, 1000L, 1, true, false, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -7900,9 +7924,9 @@ public void testFederationAttachesToRemoteBrokerWithWildcardRoutingDisabled() th final String actualAddress = getTestName() + ".A"; final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test", true); @@ -7975,9 +7999,9 @@ public void testFederationReceiverAttachedToWildcardAddressWhenAutoCreateAddress server.addAddressInfo(new AddressInfo(SimpleString.of(actualAddress), RoutingType.MULTICAST)); final Map remoteSourceProperties = new HashMap<>(); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE, true); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - remoteSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 1L); + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 1L); try (ProtonTestClient peer = new ProtonTestClient()) { scriptFederationConnectToRemote(peer, "test", true); @@ -8037,6 +8061,314 @@ public void testFederationReceiverAttachedToWildcardAddressWhenAutoCreateAddress } } + @Test + @Timeout(20) + public void testFederationAddressReceiverIndicatesNoAutoCreateWhenConfiguredNotToRequestIt() throws Exception { + try (ProtonTestServer peer = new ProtonTestServer()) { + peer.expectSASLAnonymousConnect(); + peer.expectOpen().respond(); + peer.expectBegin().respond(); + peer.expectAttach().ofSender() + .withProperty(FEDERATION_VERSION.toString(), FEDERATION_V2) + .withDesiredCapability(FEDERATION_CONTROL_LINK.toString()) + .respond() + .withProperty(FEDERATION_VERSION.toString(), FEDERATION_V2) + .withOfferedCapabilities(FEDERATION_CONTROL_LINK.toString()); + peer.expectAttach().ofReceiver() + .withSenderSettleModeSettled() + .withSource().withDynamic(true) + .and() + .withDesiredCapability(FEDERATION_EVENT_LINK.toString()) + .respondInKind() + .withTarget().withAddress("test-dynamic-events"); + peer.expectFlow().withLinkCredit(10); + peer.start(); + + final URI remoteURI = peer.getServerURI(); + logger.info("Test started, peer listening on: {}", remoteURI); + + final AMQPFederationAddressPolicyElement receiveFromAddress = new AMQPFederationAddressPolicyElement(); + receiveFromAddress.setName("address-policy"); + receiveFromAddress.addToIncludes("test"); + receiveFromAddress.setAutoCreate(false); + receiveFromAddress.setAutoDelete(false); + receiveFromAddress.setAutoDeleteDelay(-1L); + receiveFromAddress.setAutoDeleteMessageCount(-1L); + + final AMQPFederatedBrokerConnectionElement element = new AMQPFederatedBrokerConnectionElement(); + element.setName(getTestName()); + element.addLocalAddressPolicy(receiveFromAddress); + element.addProperty(ADDRESS_RECEIVER_IDLE_TIMEOUT, 0); + + final AMQPBrokerConnectConfiguration amqpConnection = + new AMQPBrokerConnectConfiguration(getTestName(), "tcp://" + remoteURI.getHost() + ":" + remoteURI.getPort()); + amqpConnection.setReconnectAttempts(0);// No reconnects + amqpConnection.addElement(element); + + server.getConfiguration().addAMQPConnection(amqpConnection); + server.start(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + + final Map expectedSourceProperties = new HashMap<>(); + expectedSourceProperties.put(AUTO_CREATE, false); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, -1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); + + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_ADDRESS_RECEIVER.toString()) + .withName(allOf(containsString(getTestName()), + containsString("test"), + containsString("address-receiver"), + containsString(server.getNodeID().toString()))) + .withProperty(FEDERATED_ADDRESS_SOURCE_PROPERTIES.toString(), expectedSourceProperties) + .withProperty(FEDERATION_POLICY_NAME.toString(), "address-policy") + .withSource().withAddress(startsWith("test::federation." + getTestName() + ".policy.address-policy.")).and() + .respond() + .withOfferedCapabilities(FEDERATION_ADDRESS_RECEIVER.toString()); + peer.expectFlow().withLinkCredit(1000); + + server.createQueue(QueueConfiguration.of("test").setRoutingType(RoutingType.MULTICAST) + .setAddress("test") + .setAutoCreated(false)); + + Wait.assertTrue(() -> server.queueQuery(SimpleString.of("test")).isExists(), 5000, 100); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectFlow().withLinkCredit(1000).withDrain(true) + .respond() + .withLinkCredit(0).withDeliveryCount(1000).withDrain(true); + peer.expectDetach().respond(); + + // This should trigger the federation consumer to be shutdown as the statically defined queue + // should be the only remaining demand on the address. + logger.info("Removing Queues from federated address to eliminate demand"); + server.destroyQueue(SimpleString.of("test")); + Wait.assertFalse(() -> server.queueQuery(SimpleString.of("test")).isExists()); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + } + } + + @Test + @Timeout(20) + public void testRemoteBrokerAcceptsAddressPolicyWithAutoCreateDisabledAndRequestsItForReceivers() throws Exception { + server.start(); + + final ArrayList includes = new ArrayList<>(); + includes.add(getTestName()); + final ArrayList excludes = new ArrayList<>(); + includes.add("address3"); + + final FederationReceiveFromAddressPolicy policy = + new FederationReceiveFromAddressPolicy("test-address-policy", + false, false, 0L, 0L, 1, true, false, + includes, excludes, null, null, + DEFAULT_WILDCARD_CONFIGURATION); + + + final Map expectedSourceProperties = new HashMap<>(); + expectedSourceProperties.put(AUTO_CREATE, false); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 0L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, "test", true); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectDisposition().withSettled(true).withState().accepted(); + + sendAddresPolicyToRemote(peer, policy); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_ADDRESS_RECEIVER.toString()) + .withName(allOf(containsString(getTestName()), + containsString("test"), + containsString("address-receiver"), + containsString(server.getNodeID().toString()))) + .withProperty(FEDERATED_ADDRESS_SOURCE_PROPERTIES.toString(), expectedSourceProperties) + .withProperty(FEDERATION_POLICY_NAME.toString(), "test-address-policy") + .withSource().withAddress(startsWith(getTestName() + "::federation.test.policy.test-address-policy.")).and() + .respond() + .withOfferedCapabilities(FEDERATION_ADDRESS_RECEIVER.toString()); + peer.expectFlow().withLinkCredit(1000); + + final ConnectionFactory factory = CFUtil.createConnectionFactory("AMQP", "tcp://localhost:" + AMQP_PORT); + + try (Connection connection = factory.createConnection()) { + final Session session = connection.createSession(Session.AUTO_ACKNOWLEDGE); + session.createConsumer(session.createTopic(getTestName())); + + connection.start(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + } + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testReceiverWithoutCreateAddressGetsEventWhenQueueAppearsLater() throws Exception { + final String addressName = getTestName(); + + // Don't allow the user to create so that we know the no-create option is acted on as + // the attach would fail otherwise + addFedUser(server, addressName, false, true); + server.start(); + + final Map addressSourceProperties = new HashMap<>(); + addressSourceProperties.put(AUTO_CREATE, false); + addressSourceProperties.put(AUTO_DELETE, false); + addressSourceProperties.put(AUTO_DELETE_DELAY, 0L); + addressSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + final MessageAnnotationsMatcher maMatcher = new MessageAnnotationsMatcher(true); + maMatcher.withEntry(EVENT_TYPE.toString(), Matchers.is(REQUESTED_ADDRESS_ADDED)); + final Map eventMap = new LinkedHashMap<>(); + eventMap.put(REQUESTED_ADDRESS_NAME, addressName); + + final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(eventMap); + final TransferPayloadCompositeMatcher payloadMatcher = new TransferPayloadCompositeMatcher(); + payloadMatcher.setMessageAnnotationsMatcher(maMatcher); + payloadMatcher.addMessageContentMatcher(bodyMatcher); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, federationUser, federationPass, "test", false, true, true); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofSender().withName(addressName) + .withOfferedCapabilities(FEDERATION_ADDRESS_RECEIVER.toString()) + .withNullSource(); // Pending close + peer.expectDetach().withError(AmqpError.NOT_FOUND.toString()).respond(); + + // Connect to remote as if an address had demand and matched our federation policy + // This uses the allowed address so it should attach without issue. + peer.remoteAttach().ofReceiver() + .withDesiredCapabilities(FEDERATION_ADDRESS_RECEIVER.toString()) + .withName(addressName) + .withSenderSettleModeUnsettled() + .withReceivervSettlesFirst() + .withProperty(FEDERATION_POLICY_NAME.toString(), "test-address-policy") + .withProperty(FEDERATED_ADDRESS_SOURCE_PROPERTIES.toString(), addressSourceProperties) + .withSource().withDurabilityOfNone() + .withExpiryPolicyOnLinkDetach() + .withAddress(addressName) + .withCapabilities("topic") + .and() + .withTarget().and() + .now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectTransfer().withPayload(payloadMatcher).accept(); // Address added event + + // Manually add the address and a queue binding to trigger event to notify the peer. + server.addAddressInfo(new AddressInfo(SimpleString.of(addressName), RoutingType.MULTICAST)); + server.createQueue(QueueConfiguration.of(addressName).setRoutingType(RoutingType.MULTICAST) + .setAddress(addressName) + .setAutoCreated(false)); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testRemoteBrokerAcceptsAddressPolicyWithoutSomeConfigurationAndNewOptionsThatItIgnores() throws Exception { + server.start(); + + final Map expectedSourceProperties = new HashMap<>(); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 0L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, "test", true); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectDisposition().withSettled(true).withState().accepted(); + + sendNonStandardAddresPolicyToRemote(peer, "test-address-policy", getTestName()); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_ADDRESS_RECEIVER.toString()) + .withName(allOf(containsString(getTestName()), + containsString("test"), + containsString("address-receiver"), + containsString(server.getNodeID().toString()))) + .withProperty(FEDERATED_ADDRESS_SOURCE_PROPERTIES.toString(), expectedSourceProperties) + .withProperty(FEDERATION_POLICY_NAME.toString(), "test-address-policy") + .withSource().withAddress(startsWith(getTestName() + "::federation.test.policy.test-address-policy.")).and() + .respond() + .withOfferedCapabilities(FEDERATION_ADDRESS_RECEIVER.toString()); + peer.expectFlow().withLinkCredit(1000); + + final ConnectionFactory factory = CFUtil.createConnectionFactory("AMQP", "tcp://localhost:" + AMQP_PORT); + + try (Connection connection = factory.createConnection()) { + final Session session = connection.createSession(Session.AUTO_ACKNOWLEDGE); + session.createConsumer(session.createTopic(getTestName())); + + connection.start(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + } + + server.stop(); + } + } + + protected void addFedUser(ActiveMQServer server, String address, boolean createAddress, boolean createQueue) { + ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); + + securityManager.getConfiguration().addUser(federationUser, federationPass); + securityManager.getConfiguration().addRole(federationUser, getTestName()); + + HierarchicalRepository> securityRepository = server.getSecurityRepository(); + Set userRoles = new HashSet<>(); + userRoles.add(new Role(getTestName(), + true, true, createQueue, false, createQueue, false, true, true, createAddress, false, false, false)); + + Set federateRoles = new HashSet<>(); + federateRoles.add(new Role(getTestName(), + true, true, true, true, true, true, true, true, true, true, false, false)); + + securityRepository.addMatch(address, userRoles); + securityRepository.addMatch(FEDERATION_BASE_VALIDATION_ADDRESS + ".#", federateRoles); // Allow federation operations + + server.getConfiguration().setSecurityEnabled(true); + } + protected void configureSecurity(ActiveMQServer server, String allowed, String restricted, String... userAllowedOnly) { ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); @@ -8114,11 +8446,12 @@ private static void sendAddresPolicyToRemote(ProtonTestClient peer, FederationRe final Map policyMap = new LinkedHashMap<>(); policyMap.put(POLICY_NAME, policy.getPolicyName()); - policyMap.put(ADDRESS_AUTO_DELETE, policy.isAutoDelete()); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); - policyMap.put(ADDRESS_MAX_HOPS, policy.getMaxHops()); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, policy.isEnableDivertBindings()); + policyMap.put(AUTO_CREATE, policy.isAutoCreate()); + policyMap.put(AUTO_DELETE, policy.isAutoDelete()); + policyMap.put(AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); + policyMap.put(AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); + policyMap.put(MAX_HOPS, policy.getMaxHops()); + policyMap.put(ENABLE_DIVERT_BINDINGS, policy.isEnableDivertBindings()); if (!policy.getIncludes().isEmpty()) { policyMap.put(ADDRESS_INCLUDES, new ArrayList<>(policy.getIncludes())); @@ -8148,6 +8481,26 @@ private static void sendAddresPolicyToRemote(ProtonTestClient peer, FederationRe .now(); } + private static void sendNonStandardAddresPolicyToRemote(ProtonTestClient peer, String policyName, String included) { + final Map policyMap = new LinkedHashMap<>(); + + // These are required, everything else is optional as shown by using this policy + policyMap.put(POLICY_NAME, policyName); + policyMap.put(MAX_HOPS, 0); + policyMap.put(ADDRESS_INCLUDES, List.of(included)); + + // Some new unknown field which should be ignored. + policyMap.put("SOME_NEW_BOOLEAN", true); + policyMap.put("SOME_NEW_NUMBER", 1L); + + peer.remoteTransfer().withDeliveryId(0) + .withMessageAnnotations().withAnnotation(OPERATION_TYPE.toString(), ADD_ADDRESS_POLICY) + .also() + .withBody().withValue(policyMap) + .also() + .now(); + } + // Use this method to script the initial handshake that a broker that is establishing // a federation connection with a remote broker instance would perform. private static void scriptFederationConnectToRemote(ProtonTestClient peer, String federationName) { @@ -8174,6 +8527,10 @@ private static void scriptFederationConnectToRemote(ProtonTestClient peer, Strin scriptFederationConnectToRemote(peer, user, password, federationName, AmqpSupport.AMQP_CREDITS_DEFAULT, AmqpSupport.AMQP_LOW_CREDITS_DEFAULT, false, false, fqqnAddressSubs); } + private static void scriptFederationConnectToRemote(ProtonTestClient peer, String user, String password, String federationName, boolean eventsSender, boolean eventsReceiver, boolean fqqnAddressSubs) { + scriptFederationConnectToRemote(peer, user, password, federationName, AmqpSupport.AMQP_CREDITS_DEFAULT, AmqpSupport.AMQP_LOW_CREDITS_DEFAULT, eventsSender, eventsReceiver, fqqnAddressSubs); + } + private static void scriptFederationConnectToRemote(ProtonTestClient peer, String user, String password, String federationName, int amqpCredits, int amqpLowCredits, boolean eventsSender, boolean eventsReceiver, boolean fqqnAddressSubs) { final String federationControlLinkName = "Federation:control:" + UUID.randomUUID().toString(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConfigurationReloadTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConfigurationReloadTest.java index 49791026bf28..32821ef69d44 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConfigurationReloadTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConfigurationReloadTest.java @@ -59,9 +59,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_RECEIVER_IDLE_TIMEOUT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_ADDRESS_RECEIVER; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_CONTROL_LINK; @@ -137,9 +138,10 @@ public void testFederationConfigurationWithoutChangesIsIgnoredOnUpdate() throws server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -253,9 +255,10 @@ public void testFederationConnectsToSecondPeerWhenConfigurationUpdatedWithNewCon server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -380,9 +383,10 @@ public void testFederationDisconnectsFromExistingPeerIfConfigurationRemoved() th server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer.waitForScriptToComplete(5, TimeUnit.SECONDS); peer.expectAttach().ofReceiver() @@ -486,9 +490,10 @@ public void testFederationUpdatesPolicyAndFederatesQueueInsteadOfAddress() throw server.addAddressInfo(new AddressInfo(SimpleString.of("test"), RoutingType.MULTICAST)); final Map expectedSourceProperties = new HashMap<>(); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE, true); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_DELAY, 10_000L); - expectedSourceProperties.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 10_000L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); peer1.waitForScriptToComplete(5, TimeUnit.SECONDS); peer1.expectAttach().ofReceiver() @@ -657,11 +662,11 @@ public void testReloadAmqpConnectionAddressPolicyMatches() throws Exception { public void testReloadAmqpConnectionQueuePolicyMatches() throws Exception { server.start(); server.createQueue(QueueConfiguration.of("queue1").setRoutingType(RoutingType.ANYCAST) - .setAddress("queue1") - .setAutoCreated(false)); + .setAddress("queue1") + .setAutoCreated(false)); server.createQueue(QueueConfiguration.of("queue2").setRoutingType(RoutingType.ANYCAST) - .setAddress("queue2") - .setAutoCreated(false)); + .setAddress("queue2") + .setAutoCreated(false)); final Path brokerXML = getTestDirfile().toPath().resolve("broker.xml"); final URL url1 = RedeployTest.class.getClassLoader().getResource("reload-amqp-federated-queues.xml"); @@ -747,8 +752,8 @@ public void testReloadAmqpConnectionQueuePolicyMatches() throws Exception { public void testReloadAmqpConnectionAddressPolicyReplacedWithQueuePolicy() throws Exception { server.start(); server.createQueue(QueueConfiguration.of("queue1").setRoutingType(RoutingType.ANYCAST) - .setAddress("queue1") - .setAutoCreated(false)); + .setAddress("queue1") + .setAutoCreated(false)); final Path brokerXML = getTestDirfile().toPath().resolve("broker.xml"); final URL url1 = RedeployTest.class.getClassLoader().getResource("reload-amqp-federated-addresses.xml"); @@ -821,11 +826,11 @@ public void testReloadAmqpConnectionAddressPolicyReplacedWithQueuePolicy() throw public void testReloadAmqpConnectionQueuePolicyMatchesFromBrokerProperties() throws Exception { server.start(); server.createQueue(QueueConfiguration.of("queue1").setRoutingType(RoutingType.ANYCAST) - .setAddress("queue1") - .setAutoCreated(false)); + .setAddress("queue1") + .setAutoCreated(false)); server.createQueue(QueueConfiguration.of("queue2").setRoutingType(RoutingType.ANYCAST) - .setAddress("queue2") - .setAutoCreated(false)); + .setAddress("queue2") + .setAutoCreated(false)); final Path brokerXML = getTestDirfile().toPath().resolve("broker.xml"); final Path brokerProperties = getTestDirfile().toPath().resolve("broker.properties"); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConnectTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConnectTest.java index 4b6c83c429ef..3bee020bcb2f 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConnectTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationConnectTest.java @@ -63,14 +63,15 @@ import static org.apache.activemq.artemis.protocol.amqp.connect.AMQPBrokerConnectionConstants.BROKER_CONNECTION_INFO; import static org.apache.activemq.artemis.protocol.amqp.connect.AMQPBrokerConnectionConstants.CONNECTION_NAME; import static org.apache.activemq.artemis.protocol.amqp.connect.AMQPBrokerConnectionConstants.NODE_ID; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ENABLE_DIVERT_BINDINGS; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ALLOW_WILDCARD_GROUPINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ENABLE_DIVERT_BINDINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ALLOW_WILDCARD_GROUPINGS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_EXCLUDES; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_INCLUDES; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_MAX_HOPS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.MAX_HOPS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_RECEIVER_IDLE_TIMEOUT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_ADDRESS_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_QUEUE_POLICY; @@ -564,6 +565,10 @@ public void testFederationSendsReceiveFromQueuePolicyToRemoteWhenSendToIsConfigu excludes.add("h"); policyMap.put(POLICY_NAME, "test-policy"); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, 0L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 0L); policyMap.put(QUEUE_INCLUDE_FEDERATED, true); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 42); policyMap.put(QUEUE_INCLUDES, includes); @@ -639,6 +644,10 @@ public void testFederationSendsReceiveFromQueuePolicyToRemoteWhenSendToIsConfigu excludes.add("h"); policyMap.put(POLICY_NAME, "test-policy"); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, 0L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 0L); policyMap.put(QUEUE_INCLUDE_FEDERATED, true); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 42); policyMap.put(QUEUE_INCLUDES, includes); @@ -709,12 +718,13 @@ public void testFederationSendsReceiveFromAddressPolicyToRemoteWhenSendToIsConfi excludes.add("exclude"); policyMap.put(POLICY_NAME, "test-policy"); - policyMap.put(ADDRESS_AUTO_DELETE, true); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, 42L); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 314L); - policyMap.put(ADDRESS_MAX_HOPS, 5); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + policyMap.put(AUTO_CREATE, true); + policyMap.put(AUTO_DELETE, true); + policyMap.put(AUTO_DELETE_DELAY, 42L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 314L); + policyMap.put(MAX_HOPS, 5); + policyMap.put(ENABLE_DIVERT_BINDINGS, false); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, false); policyMap.put(ADDRESS_INCLUDES, includes); policyMap.put(ADDRESS_EXCLUDES, excludes); @@ -783,12 +793,13 @@ public void testFederationSendsReceiveFromAddressPolicyToRemoteWhenSendToIsConfi excludes.add("exclude"); policyMap.put(POLICY_NAME, "test-policy"); - policyMap.put(ADDRESS_AUTO_DELETE, true); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, 42L); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, 314L); - policyMap.put(ADDRESS_MAX_HOPS, 5); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + policyMap.put(AUTO_CREATE, true); + policyMap.put(AUTO_DELETE, true); + policyMap.put(AUTO_DELETE_DELAY, 42L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 314L); + policyMap.put(MAX_HOPS, 5); + policyMap.put(ENABLE_DIVERT_BINDINGS, false); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, false); policyMap.put(ADDRESS_INCLUDES, includes); policyMap.put(ADDRESS_EXCLUDES, excludes); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationManagementTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationManagementTest.java index 582056ea82f6..9645e759c30b 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationManagementTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationManagementTest.java @@ -69,13 +69,14 @@ import static org.apache.activemq.artemis.protocol.amqp.connect.AMQPBrokerConnectionConstants.BROKER_CONNECTION_INFO; import static org.apache.activemq.artemis.protocol.amqp.connect.AMQPBrokerConnectionConstants.CONNECTION_NAME; import static org.apache.activemq.artemis.protocol.amqp.connect.AMQPBrokerConnectionConstants.NODE_ID; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_DELAY; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_AUTO_DELETE_MSG_COUNT; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ENABLE_DIVERT_BINDINGS; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_ALLOW_WILDCARD_GROUPINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ENABLE_DIVERT_BINDINGS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ALLOW_WILDCARD_GROUPINGS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_INCLUDES; -import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_MAX_HOPS; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.MAX_HOPS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADDRESS_RECEIVER_IDLE_TIMEOUT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_ADDRESS_POLICY; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_QUEUE_POLICY; @@ -1076,12 +1077,13 @@ public void testRemoteAddressFederationTracksMessagesAtPolicyAndProducerLevels() includes.add(getTestName()); policyMap.put(POLICY_NAME, "remote-address-policy"); - policyMap.put(ADDRESS_AUTO_DELETE, false); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); - policyMap.put(ADDRESS_MAX_HOPS, 5); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + policyMap.put(AUTO_CREATE, true); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, -1L); + policyMap.put(AUTO_DELETE_MSG_COUNT, -1L); + policyMap.put(MAX_HOPS, 5); + policyMap.put(ENABLE_DIVERT_BINDINGS, false); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, false); policyMap.put(ADDRESS_INCLUDES, includes); final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(policyMap); @@ -1279,12 +1281,13 @@ public void testRemoteAddressFederationTrackingCleanedUpOnBrokerConnectionStoppe includes.add(getTestName()); policyMap.put(POLICY_NAME, "remote-address-policy"); - policyMap.put(ADDRESS_AUTO_DELETE, false); - policyMap.put(ADDRESS_AUTO_DELETE_DELAY, -1L); - policyMap.put(ADDRESS_AUTO_DELETE_MSG_COUNT, -1L); - policyMap.put(ADDRESS_MAX_HOPS, 5); - policyMap.put(ADDRESS_ENABLE_DIVERT_BINDINGS, false); - policyMap.put(ADDRESS_ALLOW_WILDCARD_GROUPINGS, false); + policyMap.put(AUTO_CREATE, true); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, -1L); + policyMap.put(AUTO_DELETE_MSG_COUNT, -1L); + policyMap.put(MAX_HOPS, 5); + policyMap.put(ENABLE_DIVERT_BINDINGS, false); + policyMap.put(ALLOW_WILDCARD_GROUPINGS, false); policyMap.put(ADDRESS_INCLUDES, includes); final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(policyMap); @@ -1407,6 +1410,10 @@ public void testRemoteQueueFederationTracksMessagesAtPolicyAndProducerLevels() t includes.add(getTestName()); policyMap.put(POLICY_NAME, "remote-queue-policy"); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, 0L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 0L); policyMap.put(QUEUE_INCLUDE_FEDERATED, false); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 64); policyMap.put(QUEUE_INCLUDES, includes); @@ -1606,6 +1613,10 @@ public void testRemoteQueueFederationTrackingCleanedUpOnBrokerConnectionStopped( includes.add(getTestName()); policyMap.put(POLICY_NAME, "remote-queue-policy"); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, 0L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 0L); policyMap.put(QUEUE_INCLUDE_FEDERATED, false); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 64); policyMap.put(QUEUE_INCLUDES, includes); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationQueuePolicyTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationQueuePolicyTest.java index 405212455208..f3396108c4bc 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationQueuePolicyTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPFederationQueuePolicyTest.java @@ -59,6 +59,7 @@ import org.apache.activemq.artemis.core.security.Role; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.Divert; +import org.apache.activemq.artemis.core.server.QueueQueryResult; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.core.server.transformer.Transformer; import org.apache.activemq.artemis.core.settings.HierarchicalRepository; @@ -96,6 +97,10 @@ import static org.apache.activemq.artemis.core.config.WildcardConfiguration.DEFAULT_WILDCARD_CONFIGURATION; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConfiguration.DEFAULT_PULL_CREDIT_BATCH_SIZE; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.ADD_QUEUE_POLICY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_CREATE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_DELAY; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.AUTO_DELETE_MSG_COUNT; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.EVENT_TYPE; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_BASE_VALIDATION_ADDRESS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.FEDERATION_CONFIGURATION; @@ -131,6 +136,7 @@ import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.TRANSFORMER_PROPERTIES_MAP; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationConstants.USE_MODIFIED_FOR_TRANSIENT_DELIVERY_ERRORS; import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationPolicySupport.DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT; +import static org.apache.activemq.artemis.protocol.amqp.connect.federation.AMQPFederationPolicySupport.FEDERATED_QUEUE_SOURCE_PROPERTIES; import static org.apache.activemq.artemis.protocol.amqp.proton.AMQPTunneledMessageConstants.AMQP_TUNNELED_CORE_LARGE_MESSAGE_FORMAT; import static org.apache.activemq.artemis.protocol.amqp.proton.AMQPTunneledMessageConstants.AMQP_TUNNELED_CORE_MESSAGE_FORMAT; import static org.hamcrest.CoreMatchers.allOf; @@ -139,9 +145,11 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Tests for AMQP Broker federation handling of the receive from and send to queue policy configuration handling. @@ -1390,8 +1398,6 @@ public void testInboundMessageRoutedToReceiverOnLocalQueue() throws Exception { } } - // TODO: Decide how to handle priority on queue consumers and then maybe port these tests to the bridge - @Test @Timeout(20) public void testFederationCreatesQueueReceiverLinkWithDefaultPrioirty() throws Exception { @@ -1559,8 +1565,6 @@ private void doTestFederationCreatesQueueReceiverWithCorrectPriorityOffset(boole } } - // TODO: See above - @Test @Timeout(20) public void testLinkCreatedForEachDistinctQueueMatchInSameConfiguredPolicyWithSameAddressMatch() throws Exception { @@ -1683,6 +1687,7 @@ public void testRemoteBrokerAcceptsQueuePolicyFromControlLink() throws Exception final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, excludes, null, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -1727,6 +1732,7 @@ public void testRemoteBrokerAcceptsQueuePolicyFromControlLinkWithTransformerConf final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, excludes, null, transformerConfiguration, DEFAULT_WILDCARD_CONFIGURATION); @@ -1765,6 +1771,7 @@ public void testRemoteFederatesQueueWhenDemandIsApplied() throws Exception { final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -1834,6 +1841,7 @@ public void testRemoteFederatesQueueWhenDemandIsAppliedUsingControllerDefinedLin final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -1908,6 +1916,7 @@ public void testRemoteFederatesQueueWhenDemandIsAppliedUsingPolicyDefinedLinkCre final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -1986,6 +1995,7 @@ public void testRemoteFederatesQueueAndAppliesTransformerWhenDemandIsApplied() t final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, null, properties, transformerConfiguration, DEFAULT_WILDCARD_CONFIGURATION); @@ -3384,6 +3394,10 @@ public void testFederationCreatesEventSenderAndReceiverWhenLocalAndRemotePolicie policyMap.put(QUEUE_INCLUDE_FEDERATED, false); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 64); policyMap.put(QUEUE_INCLUDES, includes); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, 0L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 0L); final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(policyMap); final TransferPayloadCompositeMatcher payloadMatcher = new TransferPayloadCompositeMatcher(); @@ -3464,6 +3478,10 @@ public void testFederationSendsRemotePolicyIfEventsSenderLinkRejected() throws E policyMap.put(POLICY_NAME, "test-policy"); policyMap.put(QUEUE_INCLUDE_FEDERATED, false); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, 64); + policyMap.put(AUTO_CREATE, false); + policyMap.put(AUTO_DELETE, false); + policyMap.put(AUTO_DELETE_DELAY, 0L); + policyMap.put(AUTO_DELETE_MSG_COUNT, 0L); policyMap.put(QUEUE_INCLUDES, includes); final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(policyMap); @@ -5246,6 +5264,7 @@ private void testRemoteFederationRespectsUseModifiedForRejectConfiguration(boole final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -5579,6 +5598,7 @@ public void testRemoteFederationDoesNotCreateLinksForQueuesItCannotWriteTo() thr final FederationReceiveFromQueuePolicy policy = new FederationReceiveFromQueuePolicy("test-queue-policy", + false, false, 0, 0, true, -2, includes, null, properties, null, DEFAULT_WILDCARD_CONFIGURATION); @@ -5660,11 +5680,11 @@ public void testRemoteBrokerFederationReceiverRejectedWhenSecurityRestricted() t configureSecurity(server, allowedQueue, restrictedQueue); server.start(); server.createQueue(QueueConfiguration.of(allowedQueue).setRoutingType(RoutingType.ANYCAST) - .setAddress(allowedQueue) - .setAutoCreated(false)); + .setAddress(allowedQueue) + .setAutoCreated(false)); server.createQueue(QueueConfiguration.of(restrictedQueue).setRoutingType(RoutingType.ANYCAST) - .setAddress(restrictedQueue) - .setAutoCreated(false)); + .setAddress(restrictedQueue) + .setAutoCreated(false)); final String allowedFQQN = allowedQueue + "::" + allowedQueue; final String restrictedFQQN = restrictedQueue + "::" + restrictedQueue; @@ -5724,6 +5744,518 @@ public void testRemoteBrokerFederationReceiverRejectedWhenSecurityRestricted() t } } + @Test + @Timeout(20) + public void testFederationCreatesQueueReceiverWithConfiguredAutoCreateSettings() throws Exception { + try (ProtonTestServer peer = new ProtonTestServer()) { + peer.expectSASLAnonymousConnect(); + peer.expectOpen().respond(); + peer.expectBegin().respond(); + peer.expectAttach().ofSender() + .withDesiredCapability(FEDERATION_CONTROL_LINK.toString()) + .respond() + .withOfferedCapabilities(FEDERATION_CONTROL_LINK.toString()); + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_EVENT_LINK.toString()) + .respondInKind(); + peer.expectFlow().withLinkCredit(10); + peer.start(); + + final URI remoteURI = peer.getServerURI(); + logger.info("Connect test started, peer listening on: {}", remoteURI); + + final AMQPFederationQueuePolicyElement receiveFromQueue = new AMQPFederationQueuePolicyElement(); + receiveFromQueue.setName("queue-policy"); + receiveFromQueue.addToIncludes("test", "test"); + receiveFromQueue.setAutoCreate(true); + receiveFromQueue.setAutoDelete(true); + receiveFromQueue.setAutoDeleteDelay(100L); + receiveFromQueue.setAutoDeleteMessageCount(125L); + receiveFromQueue.addProperty(RECEIVER_CREDITS, "30"); + receiveFromQueue.addProperty(RECEIVER_CREDITS_LOW, "3"); + + final AMQPFederatedBrokerConnectionElement element = new AMQPFederatedBrokerConnectionElement(); + element.setName(getTestName()); + element.addLocalQueuePolicy(receiveFromQueue); + + final AMQPBrokerConnectConfiguration amqpConnection = + new AMQPBrokerConnectConfiguration(getTestName(), "tcp://" + remoteURI.getHost() + ":" + remoteURI.getPort()); + amqpConnection.setReconnectAttempts(0);// No reconnects + amqpConnection.addElement(element); + + server.getConfiguration().addAMQPConnection(amqpConnection); + server.start(); + server.createQueue(QueueConfiguration.of("test").setRoutingType(RoutingType.ANYCAST) + .setAddress("test") + .setAutoCreated(false)); + + final Map expectedSourceProperties = new HashMap<>(); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 100L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, 125L); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_QUEUE_RECEIVER.toString()) + .withName(allOf(containsString(getTestName()), + containsString("test"), + containsString("queue-receiver"), + containsString(server.getNodeID().toString()))) + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), expectedSourceProperties) + .withProperty(FEDERATION_RECEIVER_PRIORITY.toString(), DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT) + .withSource().and() + .withTarget().and() + .respond() + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()); + peer.expectFlow().withLinkCredit(30); + + final ConnectionFactory factory = CFUtil.createConnectionFactory("AMQP", "tcp://localhost:" + AMQP_PORT); + + try (Connection connection = factory.createConnection()) { + final Session session = connection.createSession(Session.AUTO_ACKNOWLEDGE); + session.createConsumer(session.createQueue("test")); + + connection.start(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + } + } + } + + @Test + @Timeout(20) + public void testRemoteBrokerAcceptsQueuePolicyWithAutoCreateEnabledAndRequestsItForReceivers() throws Exception { + server.start(); + + final Collection> includes = new ArrayList<>(); + includes.add(new AbstractMap.SimpleEntry<>("#", getTestName())); + final Collection> excludes = new ArrayList<>(); + excludes.add(new AbstractMap.SimpleEntry<>("address1", "test.#")); + + final FederationReceiveFromQueuePolicy policy = + new FederationReceiveFromQueuePolicy("test-queue-policy", + true, true, 1, 2, + true, -1, includes, excludes, null, null, + DEFAULT_WILDCARD_CONFIGURATION); + + final Map expectedSourceProperties = new HashMap<>(); + expectedSourceProperties.put(AUTO_CREATE, true); + expectedSourceProperties.put(AUTO_DELETE, true); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 1L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, 2L); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, "test"); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectDisposition().withSettled(true).withState().accepted(); + + sendQueuePolicyToRemote(peer, policy); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_QUEUE_RECEIVER.toString()) + .withName(allOf(containsString(getTestName()), + containsString("test"), + containsString("queue-receiver"), + containsString(server.getNodeID().toString()))) + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), expectedSourceProperties) + .withProperty(FEDERATION_RECEIVER_PRIORITY.toString(), DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT) + .withSource().and() + .withTarget().and() + .respond() + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()); + peer.expectFlow().withLinkCredit(1000); + + final ConnectionFactory factory = CFUtil.createConnectionFactory("AMQP", "tcp://localhost:" + AMQP_PORT); + + try (Connection connection = factory.createConnection()) { + final Session session = connection.createSession(Session.AUTO_ACKNOWLEDGE); + session.createConsumer(session.createQueue(getTestName())); + + connection.start(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + } + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testFederationCreatedQueueCleanedUpAfterConnectionDroppedIfConfiguredTo() throws Exception { + doTestFederationCreatedQueueAppliesAutoDeletePolicyToCreatedQueue(true); + } + + @Test + @Timeout(20) + public void testFederationCreatedQueueNotCleanedUpAfterConnectionDroppedIfConfiguredNotTo() throws Exception { + doTestFederationCreatedQueueAppliesAutoDeletePolicyToCreatedQueue(false); + } + + private void doTestFederationCreatedQueueAppliesAutoDeletePolicyToCreatedQueue(boolean autoDelete) throws Exception { + server.getConfiguration().setAddressQueueScanPeriod(100); + server.start(); + // NOTE: We did not pre-create the queue + + final Map remoteSourceProperties = new HashMap<>(); + remoteSourceProperties.put(AUTO_CREATE, true); + + if (autoDelete) { + remoteSourceProperties.put(AUTO_DELETE, true); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 200L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); + } else { + remoteSourceProperties.put(AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE_DELAY, -1L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, -1L); + } + + final String queueName = getTestName(); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, "test"); + peer.connect("localhost", AMQP_PORT); + + // Precondition is that there were no bindings before the federation receiver attaches. + Wait.assertFalse(() -> server.queueQuery(SimpleString.of(queueName)).isExists()); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + + peer.expectAttach().ofSender().withName("federation-queue-receiver") + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withTarget().also() + .withSource().withAddress(queueName); + + // Connect to remote as if some demand had matched our federation policy + peer.remoteAttach().ofReceiver() + .withDesiredCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withName("federation-queue-receiver") + .withSenderSettleModeUnsettled() + .withReceivervSettlesFirst() + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), remoteSourceProperties) + .withSource().withDurabilityOfNone() + .withExpiryPolicyOnLinkDetach() + .withAddress(queueName) + .withCapabilities("queue") + .and() + .withTarget().and() + .now(); + peer.remoteFlow().withLinkCredit(10).now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + + // Federation consumer should be bound to the server's address + Wait.assertTrue(() -> server.bindingQuery(SimpleString.of(queueName)).getQueueNames().size() == 1, 5_000, 500); + + final SimpleString binding = server.bindingQuery(SimpleString.of(queueName)).getQueueNames().get(0); + assertNotNull(binding); + assertTrue(binding.startsWith(SimpleString.of(queueName))); + + final QueueQueryResult federationBinding = server.queueQuery(binding); + if (autoDelete) { + assertTrue(federationBinding.isAutoDelete()); + assertEquals(200, federationBinding.getAutoDeleteDelay()); + assertEquals(-1, federationBinding.getAutoDeleteMessageCount()); + } else { + assertFalse(federationBinding.isAutoDelete()); + assertEquals(-1, federationBinding.getAutoDeleteDelay()); + assertEquals(-1, federationBinding.getAutoDeleteMessageCount()); + } + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + + if (autoDelete) { + // Queue binding should eventually be auto deleted based on configuration + Wait.assertTrue(() -> server.bindingQuery(SimpleString.of(queueName)).getQueueNames().isEmpty(), 5_000, 100); + } else { + // Should still be there as it wasn't marked as auto delete as previously validated. + Wait.assertTrue(() -> server.bindingQuery(SimpleString.of(queueName)).getQueueNames().size() == 1, 1_000, 100); + } + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testReceiverWithoutCreateQueueGetsEventWhenQueueAppearsLater() throws Exception { + final String queueName = getTestName(); + + // Don't allow the user to create so that we know the no-create option is acted on as + // the attach would fail otherwise + addFedUser(server, queueName, false, false); + server.start(); + + final Map queueSourceProperties = new HashMap<>(); + queueSourceProperties.put(AUTO_CREATE, false); + queueSourceProperties.put(AUTO_DELETE, false); + queueSourceProperties.put(AUTO_DELETE_DELAY, 0L); + queueSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + server.start(); + + final MessageAnnotationsMatcher maMatcher = new MessageAnnotationsMatcher(true); + maMatcher.withEntry(EVENT_TYPE.toString(), Matchers.is(REQUESTED_QUEUE_ADDED)); + final Map eventMap = new LinkedHashMap<>(); + eventMap.put(REQUESTED_ADDRESS_NAME, queueName); + eventMap.put(REQUESTED_QUEUE_NAME, queueName); + + final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(eventMap); + final TransferPayloadCompositeMatcher payloadMatcher = new TransferPayloadCompositeMatcher(); + payloadMatcher.setMessageAnnotationsMatcher(maMatcher); + payloadMatcher.addMessageContentMatcher(bodyMatcher); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, federationUser, federationPass, "test", false, true); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofSender().withName("federation-queue-receiver") + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withTarget().also() + .withNullSource(); + peer.expectDetach().withError(AmqpError.NOT_FOUND.toString()).respond(); + + // Connect to remote as if an queue had demand and matched our federation policy + peer.remoteAttach().ofReceiver() + .withDesiredCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withName("federation-queue-receiver") + .withProperty(FEDERATION_POLICY_NAME.toString(), "test-queue-policy") + .withProperty(FEDERATION_RECEIVER_PRIORITY.toString(), DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT) + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), queueSourceProperties) + .withSenderSettleModeUnsettled() + .withReceivervSettlesFirst() + .withSource().withDurabilityOfNone() + .withExpiryPolicyOnLinkDetach() + .withAddress(queueName + "::" + queueName) + .withCapabilities("queue") + .and() + .withTarget().and() + .now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectTransfer().withPayload(payloadMatcher).accept(); // Address added event + + // Manually add the address and a queue binding to trigger event to remote peer. + server.addAddressInfo(new AddressInfo(SimpleString.of(queueName), RoutingType.ANYCAST)); + server.createQueue(QueueConfiguration.of(queueName).setRoutingType(RoutingType.ANYCAST) + .setAddress(queueName) + .setAutoCreated(false)); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testReceiverThatWantsToAutoCreateGetsNotAuthorizedWhenNotAllowedToCreateAddress() throws Exception { + doTestReceiverThatWantsToAutoCreateGetsNotAuthorizedIfPermissionRestricted(true, false); + } + + @Test + @Timeout(20) + public void testReceiverThatWantsToAutoCreateGetsNotAuthorizedWhenNotAllowedToCreateQueue() throws Exception { + doTestReceiverThatWantsToAutoCreateGetsNotAuthorizedIfPermissionRestricted(false, true); + } + + public void doTestReceiverThatWantsToAutoCreateGetsNotAuthorizedIfPermissionRestricted(boolean addressRestricted, boolean queueRestricted) throws Exception { + final String queueName = getTestName(); + + // Don't allow the user to create so that we know the no-create option is acted on as + // the attach would fail otherwise + addFedUser(server, queueName, !addressRestricted, !queueRestricted); + server.start(); + + final Map queueSourceProperties = new HashMap<>(); + queueSourceProperties.put(AUTO_CREATE, true); + queueSourceProperties.put(AUTO_DELETE, false); + queueSourceProperties.put(AUTO_DELETE_DELAY, 0L); + queueSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + server.start(); + + final MessageAnnotationsMatcher maMatcher = new MessageAnnotationsMatcher(true); + maMatcher.withEntry(EVENT_TYPE.toString(), Matchers.is(REQUESTED_QUEUE_ADDED)); + final Map eventMap = new LinkedHashMap<>(); + eventMap.put(REQUESTED_ADDRESS_NAME, queueName); + eventMap.put(REQUESTED_QUEUE_NAME, queueName); + + final EncodedAmqpValueMatcher bodyMatcher = new EncodedAmqpValueMatcher(eventMap); + final TransferPayloadCompositeMatcher payloadMatcher = new TransferPayloadCompositeMatcher(); + payloadMatcher.setMessageAnnotationsMatcher(maMatcher); + payloadMatcher.addMessageContentMatcher(bodyMatcher); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, federationUser, federationPass, "test", false, true); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofSender().withName("federation-queue-receiver") + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withTarget().also() + .withNullSource(); + peer.expectDetach().withError(AmqpError.UNAUTHORIZED_ACCESS.toString()).respond(); + + // Connect to remote as if an queue had demand and matched our federation policy + peer.remoteAttach().ofReceiver() + .withDesiredCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withName("federation-queue-receiver") + .withProperty(FEDERATION_POLICY_NAME.toString(), "test-queue-policy") + .withProperty(FEDERATION_RECEIVER_PRIORITY.toString(), DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT) + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), queueSourceProperties) + .withSenderSettleModeUnsettled() + .withReceivervSettlesFirst() + .withSource().withDurabilityOfNone() + .withExpiryPolicyOnLinkDetach() + .withAddress(queueName + "::" + queueName) + .withCapabilities("queue") + .and() + .withTarget().and() + .now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testFederationReceiverCreatesAddressUsingQueueFQQNAddressValue() throws Exception { + server.getConfiguration().setAddressQueueScanPeriod(100); + server.start(); + // NOTE: We did not pre-create the queue + + final Map remoteSourceProperties = new HashMap<>(); + remoteSourceProperties.put(AUTO_CREATE, true); + remoteSourceProperties.put(AUTO_DELETE, false); + remoteSourceProperties.put(AUTO_DELETE_DELAY, 0L); + remoteSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + final String addressName = getTestName() + "Address"; + final String queueName = getTestName(); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, "test"); + peer.connect("localhost", AMQP_PORT); + + // Precondition is that there were no bindings before the federation receiver attaches. + Wait.assertFalse(() -> server.queueQuery(SimpleString.of(queueName)).isExists()); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + + peer.expectAttach().ofSender().withName("federation-queue-receiver") + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withTarget().also() + .withSource().withAddress(addressName + "::" + queueName); + + // Connect to remote as if some demand had matched our federation policy + peer.remoteAttach().ofReceiver() + .withDesiredCapabilities(FEDERATION_QUEUE_RECEIVER.toString()) + .withName("federation-queue-receiver") + .withSenderSettleModeUnsettled() + .withReceivervSettlesFirst() + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), remoteSourceProperties) + .withSource().withDurabilityOfNone() + .withExpiryPolicyOnLinkDetach() + .withAddress(addressName + "::" + queueName) + .withCapabilities("queue") + .and() + .withTarget().and() + .now(); + peer.remoteFlow().withLinkCredit(10).now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + + // Federation consumer should be bound to the server's address + Wait.assertTrue(() -> server.queueQuery(SimpleString.of(queueName)).isExists(), 5_000, 500); + + final QueueQueryResult query = server.queueQuery(SimpleString.of(queueName)); + + assertTrue(query.isExists()); + assertEquals(addressName, query.getAddress().toString()); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + + server.stop(); + } + } + + @Test + @Timeout(20) + public void testRemoteBrokerAcceptsQueuePolicyWithoutSomeConfigurationAndNewOptionsThatItIgnores() throws Exception { + server.start(); + + final Map expectedSourceProperties = new HashMap<>(); + expectedSourceProperties.put(AUTO_CREATE, false); + expectedSourceProperties.put(AUTO_DELETE, false); + expectedSourceProperties.put(AUTO_DELETE_DELAY, 0L); + expectedSourceProperties.put(AUTO_DELETE_MSG_COUNT, 0L); + + try (ProtonTestClient peer = new ProtonTestClient()) { + scriptFederationConnectToRemote(peer, "test"); + peer.connect("localhost", AMQP_PORT); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectDisposition().withSettled(true).withState().accepted(); + + sendNonStandardQueuePolicyToRemote(peer, "test-address-policy", getTestName()); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectAttach().ofReceiver() + .withDesiredCapability(FEDERATION_QUEUE_RECEIVER.toString()) + .withName(allOf(containsString(getTestName()), + containsString("test"), + containsString("queue-receiver"), + containsString(server.getNodeID().toString()))) + .withProperty(FEDERATED_QUEUE_SOURCE_PROPERTIES.toString(), expectedSourceProperties) + .withProperty(FEDERATION_RECEIVER_PRIORITY.toString(), DEFAULT_QUEUE_RECEIVER_PRIORITY_ADJUSTMENT) + .withSource().and() + .withTarget().and() + .respond() + .withOfferedCapabilities(FEDERATION_QUEUE_RECEIVER.toString()); + peer.expectFlow().withLinkCredit(1000); + + final ConnectionFactory factory = CFUtil.createConnectionFactory("AMQP", "tcp://localhost:" + AMQP_PORT); + + try (Connection connection = factory.createConnection()) { + final Session session = connection.createSession(Session.AUTO_ACKNOWLEDGE); + session.createConsumer(session.createQueue(getTestName())); + + connection.start(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.expectClose(); + peer.remoteClose().now(); + + peer.waitForScriptToComplete(5, TimeUnit.SECONDS); + peer.close(); + } + + server.stop(); + } + } + private static void sendQueueAddedEvent(ProtonTestPeer peer, String address, String queue, int handle, int deliveryId) { final Map eventMap = new LinkedHashMap<>(); eventMap.put(REQUESTED_ADDRESS_NAME, address); @@ -5772,6 +6304,10 @@ private void sendQueuePolicyToRemote(ProtonTestClient peer, FederationReceiveFro policyMap.put(POLICY_NAME, policy.getPolicyName()); policyMap.put(QUEUE_INCLUDE_FEDERATED, policy.isIncludeFederated()); policyMap.put(QUEUE_PRIORITY_ADJUSTMENT, policy.getPriorityAjustment()); + policyMap.put(AUTO_CREATE, policy.isAutoCreate()); + policyMap.put(AUTO_DELETE, policy.isAutoDelete()); + policyMap.put(AUTO_DELETE_DELAY, policy.getAutoDeleteDelay()); + policyMap.put(AUTO_DELETE_MSG_COUNT, policy.getAutoDeleteMessageCount()); if (!policy.getIncludes().isEmpty()) { final List flattenedIncludes = new ArrayList<>(policy.getIncludes().size() * 2); @@ -5814,6 +6350,26 @@ private void sendQueuePolicyToRemote(ProtonTestClient peer, FederationReceiveFro .now(); } + private static void sendNonStandardQueuePolicyToRemote(ProtonTestClient peer, String policyName, String included) { + final Map policyMap = new LinkedHashMap<>(); + + // These are required, everything else is optional as shown by using this policy + policyMap.put(POLICY_NAME, policyName); + + // Some new unknown field which should be ignored. + policyMap.put("SOME_NEW_BOOLEAN", true); + policyMap.put("SOME_NEW_NUMBER", 1L); + + policyMap.put(QUEUE_INCLUDES, List.of("#", included)); + + peer.remoteTransfer().withDeliveryId(0) + .withMessageAnnotations().withAnnotation(OPERATION_TYPE.toString(), ADD_QUEUE_POLICY) + .also() + .withBody().withValue(policyMap) + .also() + .now(); + } + // Use this method to script the initial handshake that a broker that is establishing // a federation connection with a remote broker instance would perform. private void scriptFederationConnectToRemote(ProtonTestClient peer, String federationName) { @@ -5836,6 +6392,10 @@ private void scriptFederationConnectToRemote(ProtonTestClient peer, String usern scriptFederationConnectToRemote(peer, username, password, federationName, AmqpSupport.AMQP_CREDITS_DEFAULT, AmqpSupport.AMQP_LOW_CREDITS_DEFAULT, false, false); } + private void scriptFederationConnectToRemote(ProtonTestClient peer, String username, String password, String federationName, boolean eventsSender, boolean eventsReceiver) { + scriptFederationConnectToRemote(peer, username, password, federationName, AmqpSupport.AMQP_CREDITS_DEFAULT, AmqpSupport.AMQP_LOW_CREDITS_DEFAULT, eventsSender, eventsReceiver); + } + private void scriptFederationConnectToRemote(ProtonTestClient peer, String user, String password, String federationName, int amqpCredits, int amqpLowCredits, boolean eventsSender, boolean eventsReceiver) { final String federationControlLinkName = "Federation:control:" + UUID.randomUUID().toString(); @@ -5933,13 +6493,25 @@ private void scriptFederationConnectToRemote(ProtonTestClient peer, String user, } } - @Override - protected void configureBrokerSecurity(ActiveMQServer server) { - if (isSecurityEnabled()) { - enableSecurity(server); - } else { - server.getConfiguration().setSecurityEnabled(false); - } + protected void addFedUser(ActiveMQServer server, String address, boolean createAddress, boolean createQueue) { + ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); + + securityManager.getConfiguration().addUser(federationUser, federationPass); + securityManager.getConfiguration().addRole(federationUser, getTestName()); + + HierarchicalRepository> securityRepository = server.getSecurityRepository(); + Set userRoles = new HashSet<>(); + userRoles.add(new Role(getTestName(), + true, true, createQueue, false, createQueue, false, true, true, createAddress, false, false, false)); + + Set federateRoles = new HashSet<>(); + federateRoles.add(new Role(getTestName(), + true, true, true, true, true, true, true, true, true, true, false, false)); + + securityRepository.addMatch(address, userRoles); + securityRepository.addMatch(FEDERATION_BASE_VALIDATION_ADDRESS + ".#", federateRoles); // Allow federation operations + + server.getConfiguration().setSecurityEnabled(true); } private void configureSecurity(ActiveMQServer server, String allowedQueue, String restrictedQueue) {