I was looking for a lightweight replacement for JMS (Java Messaging Service) and wanted to avoid deploying ActiveMQ or another Java JMS service/product.
Amazon SQS is a good alternative for JMS Queues - and there is also an equivalet to JMS Topics and Subscriptions using AWS SNS.
Here is what you do:
- Create a SNS Topic
- Create a SQS Queue
- Subscribe to the SNS Topic as "sqs"
- Set the Permissions of the SQS Queue to receive SNS notifications
- Publish to the SQS topic
Here the Java code snipets - other than #4 are pretty obvious.
(1) Create the SNS Topic
AmazonSNSAsyncClient m_sns = new AmazonSNSAsyncClient(credentials);
CreateTopicRequest createTopicRequest = new CreateTopicRequest("MyTopic");
CreateTopicResult createResult = m_sns.createTopic(createTopicRequest);
String m_snsName = createResult.getTopicArn();
(2) Create a SQS Queue
AmazonSQSAsyncClient m_sqs = new AmazonSQSAsyncClient(credentials);
CreateQueueRequest request = new CreateQueueRequest("MySubscription");
CreateQueueResult result = m_sqs.createQueue(request);
String m_sqsName = result.getQueueUrl();
(3) Subscribe to the SNS Topic
First, we need to get the SQS ARN (not url):
GetQueueAttributesRequest queueAttributesRequest = new GetQueueAttributesRequest(m_sqsName)
.withAttributeNames("All");
GetQueueAttributesResult queueAttributesResult = m_sqs.getQueueAttributes(queueAttributesRequest);
Map<String, String> sqsAttributeMap = queueAttributesResult.getAttributes();
String sqsArn = sqsAttributeMap.get("QueueArn");
Then subscribe to the sqsARN
SubscribeRequest subscribeRequest = new SubscribeRequest(m_snsName, "sqs", sqsArn);
SubscribeResult subscribeResult = m_sns.subscribe(subscribeRequest);
String subscriptionArn = subscribeResult.getSubscriptionArn();
(4) Set the Permission
As SNS publishes under it's own account, you need to set a permission to receive anything in your queue. This is the "little trick" to make it work.
First we need to create a Policy:
Statement statement = new Statement(Effect.Allow)
.withActions(SQSActions.SendMessage)
.withPrincipals(new Principal("*"))
.withConditions(ConditionFactory.newSourceArnCondition(m_snsName))
.withResources(new Resource(sqsArn));
Policy policy = new Policy("SubscriptionPermission")
.withStatements(statement);
An then set the queue attribute (the addPermission API is mainly for adding other AWS Account IDs)
HashMap<String, String> attributes = new HashMap<String, String>();
attributes.put("Policy", policy.toJson());
SetQueueAttributesRequest request = new SetQueueAttributesRequest(m_sqsName, attributes);
m_sqs.setQueueAttributes(request);
That's it. Works nicely.