Russell Bateman
July 2014
last update:
Here's a great tool, Nevado, for making the port of your JMS messaging layer to Amazon SQS (or even Comcast CMB) go easier. I'm corralling all the details here. I used ObjectAid to generate some light UML; here's the legend.
I need to look at this project to see if it's promising as a JMS abstraction of Amazon SQS for our use. What I've found so far is:
Here is a high-level diagram of Nevado's sessions, connections showing also Amazon SQS connectors.
Nevado's Amazon SQS connectors, queues and messages.
Nevado's Amazon SQS connector factories.
Last, for what it's worth, Nevado's mocking framework for testing purposes.
Got the Sun JMS example running using Nevado atop AWS SQS. I created an Eclipse project. I needed a properties file to solve AWS configuration. These values here are dummies that look a little bit like what you'd see, but are of no actual value.
access.key.id = AKIAIK7CONYFPBM2WKXQ access.secret.key = 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 queue.url = https://sqs.us-east-1.amazonaws.com/633002655422/acme-accounts
The JAR libraries I used I quickly found, mostly from Maven sites:
Here's the sample code. Highlighting are those lines which are necessarily Nevado while the rest of what's going on is pure JMS.
import java.net.URL; import java.util.ResourceBundle; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import org.skyscreamer.nevado.jms.NevadoConnectionFactory; import org.skyscreamer.nevado.jms.connector.amazonaws.AmazonAwsSQSConnectorFactory; import org.skyscreamer.nevado.jms.destination.NevadoQueue; public class HelloWorldMessage { public static void main( String[] args ) throws Exception { ResourceBundle bundle = ResourceBundle.getBundle( "resources/aws" ); String accessKey = bundle.getString( "access.key.id" ); String secretKey = bundle.getString( "access.secret.key" ); String queueUrl = bundle.getString( "queue.url" ); try { // Step 1: Create an Amazon AWS SQS connector factory for use in priming the pump. // this step is not part of the Sun example. AmazonAwsSQSConnectorFactory awsConnectorFactory = new AmazonAwsSQSConnectorFactory(); // Step 2: Instantiate an Amazon or Nevado connection factory, injecting AWS credentials. // This step replaces this line in the Sun example: // connectionFactory = new com.sun.messaging.ConnectionFactory(); ConnectionFactory connectionFactory = new NevadoConnectionFactory(); ( ( NevadoConnectionFactory ) connectionFactory ).setSqsConnectorFactory( awsConnectorFactory ); ( ( NevadoConnectionFactory ) connectionFactory ).setAwsAccessKey( accessKey ); ( ( NevadoConnectionFactory ) connectionFactory ).setAwsSecretKey( secretKey ); // Step 3: Create a connection to Amazon SQS. Connection connection = connectionFactory.createConnection(); // Step 4: Create a session from the connection. Session session = connection.createSession( false, Session.AUTO_ACKNOWLEDGE ); // Step 5: Instantiate a new JMS queue using a Nevado queue, injecting AWS queue URL. // This step replaces this line in the Sun example: // queue = new com.sun.messaging.Queue( "world" ); Queue queue = new NevadoQueue( new URL( queueUrl ) ); // Step 6: Create a message producer. MessageProducer producer = session.createProducer( queue ); // Step 7: Create and send a test message to the queue. TextMessage sendingTextMessage = session.createTextMessage(); sendingTextMessage.setText( "Hello World" ); System.out.println( "Sending Message: " + sendingTextMessage.getText() ); producer.send( sendingTextMessage ); // Step 8: Create a message consumer. MessageConsumer consumer = session.createConsumer( queue ); // Step 9: Start the connection (created in step 3). connection.start(); // Step 10: Receive a message from the queue. Message message = consumer.receive(); // Step 11: Retrieve the contents of the message. if( message instanceof TextMessage ) { TextMessage receivingTextMessage = ( TextMessage ) message; System.out.println( "Read Message: " + receivingTextMessage.getText() ); } /* -------------------------------------------------------------------------------- * Output should appear something like this: * * Sending Message: Hello World * Jul 22, 2014 10:39:11 AM org.skyscreamer.nevado.jms.connector.amazonaws.AmazonAwsSQSConnector sendMessage * INFO: Sent message to SQS f174ad51-994e-485f-91d6-578d8943b48e * Jul 22, 2014 10:39:11 AM org.skyscreamer.nevado.jms.connector.amazonaws.AmazonAwsSQSConnector receiveMessage * INFO: Received message f174ad51-994e-485f-91d6-578d8943b48e * Read Message: Hello World * -------------------------------------------------------------------------------- */ // Step 12: Close the session and connection. session.close(); connection.close(); } catch( Exception e ) { System.out.println( "Exception occurred : " + e.toString() ); e.printStackTrace(); } } }
From the sample code that now works, the essence of what we've learned about the JMS lifecycle is this:
In case I haven't flogged this horse enough, here's a diagram of the above sample. The special, Nevado classes are marked in grey, but everything else is pure JMS.