Skip to content

Commit e6e659a

Browse files
garyrussellartembilan
authored andcommitted
GH-1125: Add DeclarableCustomizer
Resolves #1125 - pull up the common `arguments` field to `AbstractDeclarable` - add `x-single-active-consumer` as a first class `QueueBuilder` argumemt * Doc polishing * Add back default ctor; fix default return from removeArgument().
1 parent 24a9388 commit e6e659a

File tree

13 files changed

+202
-60
lines changed

13 files changed

+202
-60
lines changed

spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
import java.util.Arrays;
2121
import java.util.Collection;
2222
import java.util.Collections;
23+
import java.util.HashMap;
24+
import java.util.Map;
2325

26+
import org.springframework.lang.Nullable;
2427
import org.springframework.util.Assert;
2528

2629
/**
@@ -32,12 +35,32 @@
3235
*/
3336
public abstract class AbstractDeclarable implements Declarable {
3437

35-
private volatile boolean shouldDeclare = true;
38+
private boolean shouldDeclare = true;
3639

37-
private volatile Collection<Object> declaringAdmins = new ArrayList<Object>();
40+
private Collection<Object> declaringAdmins = new ArrayList<Object>();
3841

3942
private boolean ignoreDeclarationExceptions;
4043

44+
private final Map<String, Object> arguments;
45+
46+
public AbstractDeclarable() {
47+
this(null);
48+
}
49+
50+
/**
51+
* Construct an instance with the supplied arguments, or an empty map if null.
52+
* @param arguments the arguments.
53+
* @since 2.2.2
54+
*/
55+
public AbstractDeclarable(@Nullable Map<String, Object> arguments) {
56+
if (arguments != null) {
57+
this.arguments = new HashMap<>(arguments);
58+
}
59+
else {
60+
this.arguments = new HashMap<String, Object>();
61+
}
62+
}
63+
4164
@Override
4265
public boolean shouldDeclare() {
4366
return this.shouldDeclare;
@@ -93,4 +116,18 @@ public void setAdminsThatShouldDeclare(Object... adminArgs) {
93116
this.declaringAdmins = admins;
94117
}
95118

119+
@Override
120+
public synchronized void addArgument(String argName, Object argValue) {
121+
this.arguments.put(argName, argValue);
122+
}
123+
124+
@Override
125+
public synchronized Object removeArgument(String name) {
126+
return this.arguments.remove(name);
127+
}
128+
129+
public Map<String, Object> getArguments() {
130+
return this.arguments;
131+
}
132+
96133
}

spring-amqp/src/main/java/org/springframework/amqp/core/AbstractExchange.java

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.amqp.core;
1818

19-
import java.util.HashMap;
2019
import java.util.Map;
2120

2221

@@ -38,9 +37,7 @@ public abstract class AbstractExchange extends AbstractDeclarable implements Exc
3837

3938
private final boolean autoDelete;
4039

41-
private final Map<String, Object> arguments;
42-
43-
private volatile boolean delayed;
40+
private boolean delayed;
4441

4542
private boolean internal;
4643

@@ -75,16 +72,10 @@ public AbstractExchange(String name, boolean durable, boolean autoDelete) {
7572
* @param arguments the arguments used to declare the exchange
7673
*/
7774
public AbstractExchange(String name, boolean durable, boolean autoDelete, Map<String, Object> arguments) {
78-
super();
75+
super(arguments);
7976
this.name = name;
8077
this.durable = durable;
8178
this.autoDelete = autoDelete;
82-
if (arguments != null) {
83-
this.arguments = arguments;
84-
}
85-
else {
86-
this.arguments = new HashMap<String, Object>();
87-
}
8879
}
8980

9081
@Override
@@ -105,20 +96,6 @@ public boolean isAutoDelete() {
10596
return this.autoDelete;
10697
}
10798

108-
/**
109-
* Add an argument to the arguments.
110-
* @param argName the argument name.
111-
* @param argValue the argument value.
112-
*/
113-
protected synchronized void addArgument(String argName, Object argValue) {
114-
this.arguments.put(argName, argValue);
115-
}
116-
117-
@Override
118-
public Map<String, Object> getArguments() {
119-
return this.arguments;
120-
}
121-
12299
@Override
123100
public boolean isDelayed() {
124101
return this.delayed;
@@ -156,7 +133,7 @@ public String toString() {
156133
", durable=" + this.durable +
157134
", autoDelete=" + this.autoDelete +
158135
", internal=" + this.internal +
159-
", arguments=" + this.arguments + "]";
136+
", arguments=" + getArguments() + "]";
160137
}
161138

162139
}

spring-amqp/src/main/java/org/springframework/amqp/core/Binding.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Map;
2020

21+
import org.springframework.lang.Nullable;
22+
2123
/**
2224
* Simple container collecting information to describe a binding. Takes String destination and exchange names as
2325
* arguments to facilitate wiring using code based configuration. Can be used in conjunction with {@link AmqpAdmin}, or
@@ -54,17 +56,16 @@ public enum DestinationType {
5456

5557
private final String routingKey;
5658

57-
private final Map<String, Object> arguments;
58-
5959
private final DestinationType destinationType;
6060

6161
public Binding(String destination, DestinationType destinationType, String exchange, String routingKey,
62-
Map<String, Object> arguments) {
62+
@Nullable Map<String, Object> arguments) {
63+
64+
super(arguments);
6365
this.destination = destination;
6466
this.destinationType = destinationType;
6567
this.exchange = exchange;
6668
this.routingKey = routingKey;
67-
this.arguments = arguments;
6869
}
6970

7071
public String getDestination() {
@@ -83,18 +84,14 @@ public String getRoutingKey() {
8384
return this.routingKey;
8485
}
8586

86-
public Map<String, Object> getArguments() {
87-
return this.arguments;
88-
}
89-
9087
public boolean isDestinationQueue() {
9188
return DestinationType.QUEUE.equals(this.destinationType);
9289
}
9390

9491
@Override
9592
public String toString() {
9693
return "Binding [destination=" + this.destination + ", exchange=" + this.exchange + ", routingKey="
97-
+ this.routingKey + "]";
94+
+ this.routingKey + ", arguments=" + getArguments() + "]";
9895
}
9996

10097
}

spring-amqp/src/main/java/org/springframework/amqp/core/Declarable.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Collection;
2020

21+
import org.springframework.lang.Nullable;
22+
2123
/**
2224
* Classes implementing this interface can be auto-declared
2325
* with the broker during context initialization by an {@code AmqpAdmin}.
@@ -50,4 +52,24 @@ public interface Declarable {
5052
*/
5153
boolean isIgnoreDeclarationExceptions();
5254

55+
/**
56+
* Add an argument to the declarable.
57+
* @param name the argument name.
58+
* @param value the argument value.
59+
* @since 2.2.2
60+
*/
61+
default void addArgument(String name, Object value) {
62+
// default no-op
63+
}
64+
65+
/**
66+
* Remove an argument from the declarable.
67+
* @param name the argument name.
68+
* @return the argument value or null if not present.
69+
* @since 2.2.2
70+
*/
71+
default @Nullable Object removeArgument(String name) {
72+
return null;
73+
}
74+
5375
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.amqp.core;
18+
19+
import java.util.function.Function;
20+
21+
/**
22+
* Beans of this type are invoked by the {@link AmqpAdmin} before declaring the
23+
* {@link Declarable}, allowing customization thereof.
24+
*
25+
* @author Gary Russell
26+
* @since 2.2.2
27+
*
28+
*/
29+
@FunctionalInterface
30+
public interface DeclarableCustomizer extends Function<Declarable, Declarable> {
31+
32+
}

spring-amqp/src/main/java/org/springframework/amqp/core/Queue.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public class Queue extends AbstractDeclarable implements Cloneable {
4646

4747
private final boolean autoDelete;
4848

49-
private final Map<String, Object> arguments;
50-
5149
private volatile String actualName;
5250

5351
/**
@@ -90,15 +88,17 @@ public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete
9088
* @param autoDelete true if the server should delete the queue when it is no longer in use
9189
* @param arguments the arguments used to declare the queue
9290
*/
93-
public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) {
91+
public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete,
92+
@Nullable Map<String, Object> arguments) {
93+
94+
super(arguments);
9495
Assert.notNull(name, "'name' cannot be null");
9596
this.name = name;
9697
this.actualName = StringUtils.hasText(name) ? name
9798
: (Base64UrlNamingStrategy.DEFAULT.generateName() + "_awaiting_declaration");
9899
this.durable = durable;
99100
this.exclusive = exclusive;
100101
this.autoDelete = autoDelete;
101-
this.arguments = arguments != null ? arguments : new HashMap<>();
102102
}
103103

104104
/**
@@ -138,10 +138,6 @@ public boolean isAutoDelete() {
138138
return this.autoDelete;
139139
}
140140

141-
public java.util.Map<java.lang.String, java.lang.Object> getArguments() {
142-
return this.arguments;
143-
}
144-
145141
/**
146142
* Set the name from the DeclareOk.
147143
* @param name the name.
@@ -168,25 +164,25 @@ public String getActualName() {
168164
*/
169165
public final void setMasterLocator(@Nullable String locator) {
170166
if (locator == null) {
171-
this.arguments.remove(X_QUEUE_MASTER_LOCATOR);
167+
removeArgument(X_QUEUE_MASTER_LOCATOR);
172168
}
173169
else {
174-
this.arguments.put(X_QUEUE_MASTER_LOCATOR, locator);
170+
addArgument(X_QUEUE_MASTER_LOCATOR, locator);
175171
}
176172
}
177173

178174
@Override
179175
public Object clone() { // NOSONAR - doesn't throw CloneNotSupportedException
180176
Queue queue = new Queue(this.name, this.durable, this.exclusive, // NOSONAR - doesn't need to call super.clone()
181-
this.autoDelete, new HashMap<>(this.arguments));
177+
this.autoDelete, new HashMap<>(getArguments()));
182178
queue.setActualName(this.actualName);
183179
return queue;
184180
}
185181

186182
@Override
187183
public String toString() {
188184
return "Queue [name=" + this.name + ", durable=" + this.durable + ", autoDelete=" + this.autoDelete
189-
+ ", exclusive=" + this.exclusive + ", arguments=" + this.arguments
185+
+ ", exclusive=" + this.exclusive + ", arguments=" + getArguments()
190186
+ ", actualName=" + this.actualName + "]";
191187
}
192188

spring-amqp/src/main/java/org/springframework/amqp/core/QueueBuilder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,15 @@ public QueueBuilder masterLocator(MasterLocator locator) {
233233
return withArgument("x-queue-master-locator", locator.getValue());
234234
}
235235

236+
/**
237+
* Set the 'x-single-active-consumer' queue argument.
238+
* @return the builder.
239+
* @since 2.2.2
240+
*/
241+
public QueueBuilder singleActiveConsumer() {
242+
return withArgument("x-single-active-consumer", true);
243+
}
244+
236245
/**
237246
* Set the queue argument to declare a queue of type 'quorum' instead of 'classic'.
238247
* @return the builder.

0 commit comments

Comments
 (0)