Use JMS and Azure Event Hubs with Eclipse
This post will show how to use Eclipse to build a web application that uses JMS to send AMQP 1.0 messages to Azure Event Hubs.
Background
I have been working on a project that leverages Azure Event Hubs, Azure Stream Analytics, and other related technologies to demonstrate a highly scalable IOT platform. Since many of the customers that would potentially use this solution are already familiar with Java, I decided to build a demo using Eclipse.
This post uses an environment that includes Tomcat, Eclipse, and the Azure Toolkit for Eclipse. For instructions on creating this environment, see my blog post Creating an Eclipse Development Environment for Azure.
This post follows the instructions in the article How to Use JMS with AMQP 1.0 in Azure with Eclipse, with a few slight changes and deeper explanations.
Create the Web Project
In Eclipse, choose File / New / Dynamic Web Project.
I’ll name it JMSDemo. On the Dynamic Web Project page, click the New Runtime button to define a new runtime. I am using Apache Tomcat 8.0.
On the next page, we configured the Tomcat Server by providing the root directory where Tomcat is installed, and we choose the installed JRE.
Click Finish. The Dynamic Web Project looks like this:
Add Some JSP Pages
Right-click the new WebContent folder and add a new JSP page named index.jsp.
Index.jsp
- <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
- pageEncoding="ISO-8859-1"%>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>AMQP 1.0 message sender</title>
- </head>
- <form method="post" action="sendMessages.jsp">
- <br />
- This sample sends a message to a queue.
- <br /><br />
- <div>Device ID: <input type="text" name="deviceID" /></div>
- <div>Temperature: <input type="text" name="temperature" /></div>
- <input type="submit" name="submit" value="Send Message" />
- </form>
- </html>
Right-click the new WebContent folder again and add a new JSP page, this time named sendMessages.jsp.
sendMessages.jsp
- <%@ page import="MyPackage.MyAMQPSender" language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>AMQP 1.0 page 2</title>
- </head>
- <body>
- <%
- String message = "{'DeviceId':" + request.getParameter("deviceID") + ", 'Temperature':" + request.getParameter("temperature") + "}";
- out.print("Sending message -------> " + message );
- out.print("<br />");
- try
- {
- // Send the message.
- MyAMQPSender.postMessages(message);
- out.println("Message sent successfully\n");
- }
- catch (Exception e)
- {
- out.println("Error occurred while sending message to queue.\n");
- out.println(e);
- }
- %>
- </body>
- </html>
Now that we’ve created the JSP pages, we need to implement the MyAMQPSender class.
Have Some Class
Right-click the project node in the Project Explorer pane and choose New Class. Use the following properties:
- Package: MyPackage
- Name: MyAMQPSender
Click Finish to close the dialog. Now edit the contents of the MyAMQPSender.java class:
MyAMQPSender.java
- package MyPackage;
- import javax.jms.*;
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import java.io.UnsupportedEncodingException;
- import java.util.Hashtable;
- public class MyAMQPSender {
- private static Connection connection;
- private static Session sendSession;
- private static MessageProducer sender;
- private static Context context;
- public static void postMessages(String textMessage) throws Exception
- {
- try
- {
- init();
- sendTextMessage(textMessage);
- close();
- }
- catch (Exception e)
- {
- System.out.println("Exception: " + e);
- }
- }
- private static void sendTextMessage(String textMessage) throws JMSException
- {
- BytesMessage message = null;
- byte[] utf8bytes;
- try {
- utf8bytes = textMessage.getBytes("UTF8");
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- throw new JMSException("Unable to convert to UTF8");
- }
- message = sendSession.createBytesMessage();
- message.writeBytes(utf8bytes);
- sender.send(message);
- System.out.println("Sent message with JMSMessageID = " + message.getJMSMessageID());
- }
- private static void init()
- {
- try
- {
- // Configure JNDI environment
- Hashtable<String, String> env = new Hashtable<String, String>();
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory");
- env.put(Context.PROVIDER_URL, "servicebus.properties");
- context = new InitialContext(env);
- // Lookup ConnectionFactory and Queue
- ConnectionFactory cf = (ConnectionFactory) context.lookup
- ("SBCONNECTIONFACTORY");
- Destination queue = (Destination) context.lookup("QUEUE");
- // Create Connection
- connection = cf.createConnection();
- // Create sender-side Session and MessageProducer
- sendSession = connection.createSession(false,
- Session.AUTO_ACKNOWLEDGE);
- sender = sendSession.createProducer(queue);
- }
- catch (Exception e)
- {
- System.out.println("Exception: " + e);
- }
- }
- private static void close() throws JMSException
- {
- sender.close();
- sendSession.close();
- connection.close();
- }
- }
When you add the class, you are going to see red squiggly underlines and errors all over the place. This is because we need to leverage additional libraries. Because we have already installed the Azure Toolkit for Eclipse (see my blog post Creating an Eclipse Development Environment for Azure for step-by-step instructions), we can easily add the Apache Qpid Client Libraries for JMS provided by MS Open Tech.
To add the package, right-click the project and choose Properties. Next, go to the Java Build Path node, then go to the Libraries tab. Click the Add Library button and choose Package for Apache Qpid Client Libraries for JMS (by MS Open Tech) .
Click Next, and then ensure the Include in the project deployment assembly option is selected.
Click Finish, then OK to close the Properties dialog. Your errors should now be gone.
Create an Event Hub
Using your Azure subscription (don’t have one? You can create a free trial subscription), go to https://manage.windowsazure.com and go to the Service Bus tool.
Click the New button on the bottom left of the screen and choose Service Bus / Event Hub / Custom Create.
Give it a name, choose the region closest to you, and create a new namespace.
On the next screen, specify 16 for the partition count and 7 for the message retention.
Choose OK to create the event hub. Once the event hub is created, go to the Event Hubs tab (you may need to refresh the screen) and click on the event hub that you created, then click on Connection Information.
We are going to define a shared access signature policy that enables us to only send messages to the event hub. Create a new policy named SendPolicy with Send permission.
Click Save, and the Shared Access Key Generator is shown. Copy the primary key value.
Create the servicebus.properties File
Go back to Eclipse. Right-click the project and choose New / File. Name the file servicebus.properties.
The servicebus.properties file is used to register a ConnectionFactory in JNDI. Update its contents:
Code Snippet
- # Register a ConnectionFactory in JNDI using the form:
- # connectionfactory.[jndiname] = [ConnectionURL]
- connectionfactory.SBCONNECTIONFACTORY = amqps://SendPolicy:your_url_encoded_key@your_namespace.servicebus.windows.net
- # Register some queues in JNDI using the form:
- # queue.[jndiName] = [physicalName]
- queue.QUEUE = your_queue
In the connection string, the SendPolicy value is the same name as the SAS policy that we added in the Azure management portal. The “your_url_encoded_key” is the key that we copied from the Shared Access Key Generator, but its value needs to be URL-encoded. One technique for creating a URL encoding is via the web site https://www.w3schools.com/tags/ref_urlencode.asp. Finally, the “your_queue” value needs to be updated with the name of the Event Hub that you created.
Here is a redacted version of my servicebus.properties file:
Code Snippet
- # Register a ConnectionFactory in JNDI using the form:
- # connectionfactory.[jndiname] = [ConnectionURL]
- connectionfactory.SBCONNECTIONFACTORY = amqps://SendPolicy:C9OIXEiREDACTEDWhIQ%3D@amqpdemo-ns.servicebus.windows.net
- # Register some queues in JNDI using the form:
- # queue.[jndiName] = [physicalName]
- queue.QUEUE = amqpdemo
We’ll use this file as part of our deployment project.
Create an Azure Deployment Project
We’re almost there… right-click the project in Eclipse and choose Azure / Package for Azure. I name the deployment project JMSDemoDeployment.
On the JDK page, I provide the path to my installed JDK. The storage account setting is left as “(auto)”.
On the Server tab, I provide the root path to the location where I unzipped Apache Tomcat to, and choose the Type as Apache Tomcat 8. I leave the storage account as “(auto)”.
Click Finish to close the wizard.
Now right-click the deployment project and choose Properties, then go to the Azure / Roles node. Highlight the worker role and click Edit.
Go to the Component tab and choose Add. In the Azure Role Component dialog, use the File button to locate your servicebus.properties file. The import method is copy, and the “as name” value is “servicebus.properties” . Under the deploy from package settings, the method is copy, and the “to directory” value is %CATALINA_HOME%\bin.
Click OK, OK, OK to close the windows. Click the deployment project’s node in the Project Explorer pane and choose the Run in Azure Emulator button.
After some time, you will see the output in the compute emulator that Java is running.
Go to https://localhost:8080/JMSDemo/ and you will see the following JSP page served by Tomcat within the Azure Emulator.
Enter some values then click the button and we should see the following:
We successfully sent a message to Event Hub!
In order to receive the message, we need some code to process the message. This is beyond the scope of this article, but you can refer to the Event Hub documentation for a walkthrough creating a cross-platform messaging solution between JMS and .NET. You can also learn about using Visual Studio to receive messages with EventProcessorHost to create a highly scalable solution to process massive amounts of data with parallel actions.
For More Information
Creating an Eclipse Development Environment for Azure
How to Use JMS with AMQP 1.0 in Azure with Eclipse