Skip to content

Commit 99655eb

Browse files
authored
Resolve SQS queue by ARN (#619)
Fixes #561
1 parent 1b82edb commit 99655eb

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

docs/src/main/asciidoc/sqs.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ public void queueListener(Person person) {
134134
----
135135

136136
In this example a queue listener container is started that polls the SQS `queueName` passed to the `MessageMapping`
137-
annotation. The incoming messages are converted to the target type and then the annotated method `queueListener` is invoked.
137+
annotation. The incoming messages are converted to the target type and then the annotated method `queueListener` is invoked. There are multiple options to specify the queue that should be listened to:
138+
139+
* Using the queue name. Works only for queues within the same account and region your application/sqs client is using.
140+
* Using the queue url. This allows access to a queue that is in a different region than your application/sqs client is using.
141+
* Using the queue arn. Can be used to listen to queues that are owned by another account, but live within the same region your application/sqs client uses.
138142

139143
In addition to the payload, headers can be injected in the listener methods with the `@Header` or `@Headers`
140144
annotations. `@Header` is used to inject a specific header value while `@Headers` injects a `Map<String, String>`

spring-cloud-aws-messaging/src/main/java/io/awspring/cloud/messaging/support/destination/DynamicQueueUrlDestinationResolver.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.amazonaws.services.sqs.model.GetQueueUrlResult;
2727
import com.amazonaws.services.sqs.model.QueueDoesNotExistException;
2828
import io.awspring.cloud.core.env.ResourceIdResolver;
29+
import io.awspring.cloud.core.naming.AmazonResourceName;
2930

3031
import org.springframework.messaging.core.DestinationResolutionException;
3132
import org.springframework.messaging.core.DestinationResolver;
@@ -87,7 +88,15 @@ public String resolveDestination(String name) throws DestinationResolutionExcept
8788
}
8889
else {
8990
try {
90-
GetQueueUrlResult getQueueUrlResult = this.amazonSqs.getQueueUrl(new GetQueueUrlRequest(queueName));
91+
GetQueueUrlRequest request = new GetQueueUrlRequest(queueName);
92+
93+
if (AmazonResourceName.isValidAmazonResourceName(queueName)) {
94+
AmazonResourceName resourceName = AmazonResourceName.fromString(name);
95+
request.setQueueName(resourceName.getResourceType());
96+
request.setQueueOwnerAWSAccountId(resourceName.getAccount());
97+
}
98+
99+
GetQueueUrlResult getQueueUrlResult = this.amazonSqs.getQueueUrl(request);
91100
return getQueueUrlResult.getQueueUrl();
92101
}
93102
catch (QueueDoesNotExistException e) {

spring-cloud-aws-messaging/src/test/java/io/awspring/cloud/messaging/support/destination/DynamicQueueUrlDestinationResolverTest.java

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
class DynamicQueueUrlDestinationResolverTest {
3838

3939
@Test
40-
void testAutoCreate() throws Exception {
40+
void testAutoCreate() {
4141
AmazonSQS amazonSqs = mock(AmazonSQS.class);
4242
String queueUrl = "https://foo/bar";
4343
when(amazonSqs.createQueue(new CreateQueueRequest("foo")))
@@ -50,7 +50,7 @@ void testAutoCreate() throws Exception {
5050
}
5151

5252
@Test
53-
void testAbsoluteUrl() throws Exception {
53+
void testAbsoluteUrl() {
5454
AmazonSQS amazonSqs = mock(AmazonSQS.class);
5555
DynamicQueueUrlDestinationResolver dynamicQueueDestinationResolver = new DynamicQueueUrlDestinationResolver(
5656
amazonSqs);
@@ -59,7 +59,37 @@ void testAbsoluteUrl() throws Exception {
5959
}
6060

6161
@Test
62-
void testNoAutoCreate() throws Exception {
62+
void resolveDestination_shouldResolveArnToUrl() {
63+
AmazonSQS amazonSqs = mock(AmazonSQS.class);
64+
String expectedQueueUrl = "https://sqs-amazon.aws.com/123123123/myQueue";
65+
DynamicQueueUrlDestinationResolver dynamicQueueDestinationResolver = new DynamicQueueUrlDestinationResolver(
66+
amazonSqs);
67+
when(amazonSqs.getQueueUrl(new GetQueueUrlRequest("myQueue").withQueueOwnerAWSAccountId("123123123")))
68+
.thenReturn(new GetQueueUrlResult().withQueueUrl(expectedQueueUrl));
69+
String arn = "arn:aws:sqs:eu-central-1:123123123:myQueue";
70+
assertThat(dynamicQueueDestinationResolver.resolveDestination(arn)).isEqualTo(expectedQueueUrl);
71+
}
72+
73+
@Test
74+
void resolveDestination_shouldThrowError_IfQueueDoesNotExist() {
75+
AmazonSQS amazonSqs = mock(AmazonSQS.class);
76+
AmazonServiceException exception = new QueueDoesNotExistException("AWS.SimpleQueueService.NonExistentQueue");
77+
exception.setErrorCode("AWS.SimpleQueueService.NonExistentQueue");
78+
String arn = "arn:aws:sqs:eu-central-1:123123123:myQueue";
79+
when(amazonSqs.getQueueUrl(new GetQueueUrlRequest("myQueue").withQueueOwnerAWSAccountId("123123123")))
80+
.thenThrow(exception);
81+
DynamicQueueUrlDestinationResolver dynamicQueueDestinationResolver = new DynamicQueueUrlDestinationResolver(
82+
amazonSqs);
83+
try {
84+
dynamicQueueDestinationResolver.resolveDestination(arn);
85+
}
86+
catch (DestinationResolutionException e) {
87+
assertThat(e.getMessage()).startsWith("The queue does not exist.");
88+
}
89+
}
90+
91+
@Test
92+
void testNoAutoCreate() {
6393
AmazonSQS amazonSqs = mock(AmazonSQS.class);
6494
String queueUrl = "https://foo/bar";
6595
when(amazonSqs.getQueueUrl(new GetQueueUrlRequest("foo")))
@@ -71,7 +101,7 @@ void testNoAutoCreate() throws Exception {
71101
}
72102

73103
@Test
74-
void testInvalidDestinationName() throws Exception {
104+
void testInvalidDestinationName() {
75105
AmazonSQS amazonSqs = mock(AmazonSQS.class);
76106
AmazonServiceException exception = new QueueDoesNotExistException("AWS.SimpleQueueService.NonExistentQueue");
77107
exception.setErrorCode("AWS.SimpleQueueService.NonExistentQueue");
@@ -88,7 +118,7 @@ void testInvalidDestinationName() throws Exception {
88118
}
89119

90120
@Test
91-
void testPotentiallyNoAccessToPerformGetQueueUrl() throws Exception {
121+
void testPotentiallyNoAccessToPerformGetQueueUrl() {
92122
AmazonSQS amazonSqs = mock(AmazonSQS.class);
93123
AmazonServiceException exception = new QueueDoesNotExistException("AWS.SimpleQueueService.NonExistentQueue");
94124
exception.setErrorCode("AWS.SimpleQueueService.NonExistentQueue");
@@ -107,7 +137,7 @@ void testPotentiallyNoAccessToPerformGetQueueUrl() throws Exception {
107137
}
108138

109139
@Test
110-
void resolveDestination_withResourceIdResolver_shouldUseIt() throws Exception {
140+
void resolveDestination_withResourceIdResolver_shouldUseIt() {
111141
AmazonSQS amazonSqs = mock(AmazonSQS.class);
112142
ResourceIdResolver resourceIdResolver = mock(ResourceIdResolver.class);
113143
when(resourceIdResolver.resolveToPhysicalResourceId(anyString())).thenReturn("http://queue.com");
@@ -121,7 +151,7 @@ void resolveDestination_withResourceIdResolver_shouldUseIt() throws Exception {
121151
}
122152

123153
@Test
124-
void resolveDestination_withResourceIdResolver_nonUrlId_shouldGetUrlByResolvedName() throws Exception {
154+
void resolveDestination_withResourceIdResolver_nonUrlId_shouldGetUrlByResolvedName() {
125155
String queueUrl = "http://queue.com";
126156
String resolvedQueueName = "some-queue-name";
127157
AmazonSQS amazonSqs = mock(AmazonSQS.class);
@@ -138,7 +168,7 @@ void resolveDestination_withResourceIdResolver_nonUrlId_shouldGetUrlByResolvedNa
138168
}
139169

140170
@Test
141-
void instantiation_withNullAmazonClient_shouldThrowAnError() throws Exception {
171+
void instantiation_withNullAmazonClient_shouldThrowAnError() {
142172
assertThatThrownBy(() -> new DynamicQueueUrlDestinationResolver(null, null))
143173
.isInstanceOf(IllegalArgumentException.class);
144174
}

0 commit comments

Comments
 (0)