PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/articles/service-bus-java-how-to-use-jms-api-amqp.md

https://github.com/steinmr/azure-content
Markdown | 349 lines | 252 code | 97 blank | 0 comment | 0 complexity | e2830e2dbb9ee3170f8f30e9ffa2c3fe MD5 | raw file
Possible License(s): CC-BY-3.0
  1. <properties linkid="develop-java-how-to-guides-service-bus-amqp" urlDisplayName="Service Bus AMQP" pageTitle="How to use AMQP 1.0 with the Java Service Bus API - Azure" metaKeywords="ava Messsage AMQP, Service Bus AMQP, download AMQP JMS library" description="Learn how to use the Java Message Service (JMS) with Azure Service Bus and Advanced Message Queuing Protodol (AMQP) 1.0." metaCanonical="" services="service-bus" documentationCenter="Java" title="How to use the Java Message Service (JMS) API with Service Bus & AMQP 1.0" authors="" solutions="" writer="sethm" manager="dwrede" editor="mattshel" />
  2. # How to use the Java Message Service (JMS) API with Service Bus & AMQP 1.0
  3. ##Introduction
  4. The Advanced Message Queuing Protocol (AMQP) 1.0 is an efficient, reliable, wire-level messaging protocol that you can use to build robust, cross-platform messaging applications.
  5. Support for AMQP 1.0 in Service Bus means that you can use the queuing and publish/subscribe brokered messaging features from a range of platforms using an efficient binary protocol. Furthermore, you can build applications comprised of components built using a mix of languages, frameworks, and operating systems.
  6. This how-to guide explains how to use the Service Bus brokered messaging features (queues and publish/subscribe topics) from Java applications using the popular Java Message Service (JMS) API standard. There is a companion How-to guide that explains how to do the same using the Service Bus .NET API. You can use these two guides together to learn about cross-platform messaging using AMQP 1.0.
  7. ##Getting Started with Service Bus
  8. This guide assumes that you already have a Service Bus namespace containing a queue named "queue1." If you do not, then you can create the namespace and queue using the [Azure Management Portal](http://manage.windowsazure.com). For more information about how to create Service Bus namespaces and queues, see the How-To Guide titled [How to Use Service Bus Queues](https://www.windowsazure.com/en-us/develop/net/how-to-guides/service-bus-queues/).
  9. ##Downloading the AMQP 1.0 JMS client library
  10. For information about where to download the latest version of the Apache Qpid JMS AMQP 1.0 client library, visit [http://people.apache.org/~rgodfrey/qpid-java-amqp-1-0-client-jms.html](http://people.apache.org/~rgodfrey/qpid-java-amqp-1-0-client-jms.html).
  11. You must add the following four JAR files from the Apache Qpid JMS AMQP 1.0 distribution archive to the Java CLASSPATH when building and running JMS applications with Service Bus:
  12. * geronimo-jms\_1.1\_spec-1.0.jar
  13. * qpid-amqp-1-0-client-[version].jar
  14. * qpid-amqp-1-0-client-jms-[version].jar
  15. * qpid-amqp-1-0-common-[version].jar
  16. ##Coding Java applications
  17. ### Java Naming and Directory Interface (JNDI)
  18. JMS uses the Java Naming and Directory Interface (JNDI) to create a separation between logical names and physical names. Two types of JMS objects are resolved using JNDI: ConnectionFactory and Destination. JNDI uses a provider model into which you can plug different directory services to handle name resolution duties. The Apache Qpid JMS AMQP 1.0 library comes with a simple properties file-based JNDI Provider that is configured using a properties file of the following format:
  19. # servicebus.properties - sample JNDI configuration
  20. # Register a ConnectionFactory in JNDI using the form:
  21. # connectionfactory.[jndi_name] = [ConnectionURL]
  22. connectionfactory.SBCF = amqps://[username]:[password]@[namespace].servicebus.windows.net
  23. # Register some queues in JNDI using the form
  24. # queue.[jndi_name] = [physical_name]
  25. # topic.[jndi_name] = [physical_name]
  26. queue.QUEUE = queue1
  27. <p><strong>Configuring the ConnectionFactory</strong></p>
  28. The entry used to define a **ConnectionFactory** in the Qpid Properties File JNDI Provider is of the following format:
  29. connectionfactory.[jndi_name] = [ConnectionURL]
  30. Where [jndi_name] and [ConnectionURL] have the following meanings:
  31. <table>
  32. <tr>
  33. <td>[jndi_name]</td>
  34. <td>The logical name of the ConnectionFactory. This is the name that will be resolved in the Java application using the JNDI IntialContext.lookup() method.</td>
  35. </tr>
  36. <tr>
  37. <td>[ConnectionURL]</td>
  38. <td>A URL that provides the JMS library with the information required to the AMQP broker.</td>
  39. </tr>
  40. </table>
  41. The format of the **ConnectionURL** is as follows:
  42. amqps://[username]:[password]@[namespace].servicebus.windows.net
  43. Where [namespace], [username] and [password] have the following meanings:
  44. <table>
  45. <tr>
  46. <td>[namespace]</td>
  47. <td>The Service Bus namespace obtained from the Azure Management Portal.</td>
  48. </tr>
  49. <tr>
  50. <td>[username]</td>
  51. <td>The Service Bus issuer name obtained from the Azure Management Portal.</td>
  52. </tr>
  53. <tr>
  54. <td>[password]</td>
  55. <td>URL encoded form of the Service Bus issuer key obtained from the Azure Management Portal.</td>
  56. </tr>
  57. </table>
  58. **Note**: You must URL-encode the password manually. A useful URL-encoding utility is available at [http://www.w3schools.com/tags/ref_urlencode.asp](http://www.w3schools.com/tags/ref_urlencode.asp).
  59. For example, if the information obtained from the Azure Management portal is as follows:
  60. <table>
  61. <tr>
  62. <td>Namespace:</td>
  63. <td>foo.servicebus.windows.net</td>
  64. </tr>
  65. <tr>
  66. <td>Issuer name:</td>
  67. <td>owner</td>
  68. </tr>
  69. <tr>
  70. <td>Issuer key:</td>
  71. <td>j9VYv1q33Ea+cbahWsHFYnLkEzrF0yA5SAqcLNvU7KM=</td>
  72. </tr>
  73. </table>
  74. Then in order to define a **ConnectionFactory** named "SBCF", the configuration string appears as follows:
  75. connectionfactory.SBCF = amqps://owner:j9VYv1q33Ea%2BcbahWsHFYnLkEzrF0yA5SAqcLNvU7KM%3D@foo.servicebus.windows.net
  76. <p><strong>Configuring Destinations</strong></p>
  77. The entry used to define a destination in the Qpid Properties File JNDI Provider is of the following format:
  78. queue.[jndi_name] = [physical_name]
  79. or
  80. topic.[jndi_name] = [physical_name]
  81. Where [jndi\_name] and [physical\_name] have the following meanings:
  82. <table>
  83. <tr>
  84. <td>[jndi_name]</td>
  85. <td>The logical name of the destination. This is the name that will be resolved in the Java application using the JNDI IntialContext.lookup() method.</td>
  86. </tr>
  87. <tr>
  88. <td>[physical_name]</td>
  89. <td>The name of the Service Bus entity to which the application sends or receives messages.</td>
  90. </tr>
  91. </table>
  92. **Note**: When receiving from a Service Bus topic subscription, the physical name specified in JNDI should be the name of the topic. The subscription name is provided when the durable subscription is created in the JMS application code. The [Service Bus AMQP 1.0 Developer's Guide](http://msdn.microsoft.com/en-us/library/windowsazure/jj841071.aspx) provides more details on working with Service Bus topic subscriptions from JMS.
  93. ### Writing the JMS application
  94. There are no special APIs or options required when using JMS with Service Bus. However, there are a few restrictions that will be covered later. As with any JMS application, the first thing required is configuration of the JNDI environment, to be able to resolve a **ConnectionFactory** and destinations.
  95. <p><strong>Configuring the JNDI InitialContext</strong></p>
  96. The JNDI environment is configured by passing a hashtable of configuration information into the constructor of the javax.naming.InitialContext class. The two required elements in the hashtable are the class name of the Initial Context Factory and the Provider URL. The following code shows how to configure the JNDI environment to use the Qpid properties file based JNDI Provider with a properties file named **servicebus.properties**.
  97. Hashtable<String, String> env = new Hashtable<String, String>();
  98. env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory");
  99. env.put(Context.PROVIDER_URL, "servicebus.properties");
  100. InitialContext context = new InitialContext(env);
  101. ### A simple JMS application using a Service Bus Queue
  102. The following example program sends JMS TextMessages to a Service Bus queue with the JNDI logical name of QUEUE, and receives the messages back.
  103. // SimpleSenderReceiver.java
  104. import javax.jms.*;
  105. import javax.naming.Context;
  106. import javax.naming.InitialContext;
  107. import java.io.BufferedReader;
  108. import java.io.InputStreamReader;
  109. import java.util.Hashtable;
  110. import java.util.Random;
  111. public class SimpleSenderReceiver implements MessageListener {
  112. private static boolean runReceiver = true;
  113. private Connection connection;
  114. private Session sendSession;
  115. private Session receiveSession;
  116. private MessageProducer sender;
  117. private MessageConsumer receiver;
  118. private static Random randomGenerator = new Random();
  119. public SimpleSenderReceiver() throws Exception {
  120. // Configure JNDI environment
  121. Hashtable<String, String> env = new Hashtable<String, String>();
  122. env.put(Context.INITIAL_CONTEXT_FACTORY,
  123. "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory");
  124. env.put(Context.PROVIDER_URL, "servicebus.properties");
  125. Context context = new InitialContext(env);
  126. // Lookup ConnectionFactory and Queue
  127. ConnectionFactory cf = (ConnectionFactory) context.lookup("SBCF");
  128. Destination queue = (Destination) context.lookup("QUEUE");
  129. // Create Connection
  130. connection = cf.createConnection();
  131. // Create sender-side Session and MessageProducer
  132. sendSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
  133. sender = sendSession.createProducer(queue);
  134. if (runReceiver) {
  135. // Create receiver-side Session, MessageConsumer,and MessageListener
  136. receiveSession = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
  137. receiver = receiveSession.createConsumer(queue);
  138. receiver.setMessageListener(this);
  139. connection.start();
  140. }
  141. }
  142. public static void main(String[] args) {
  143. try {
  144. if ((args.length > 0) && args[0].equalsIgnoreCase("sendonly")) {
  145. runReceiver = false;
  146. }
  147. SimpleSenderReceiver simpleSenderReceiver = new SimpleSenderReceiver();
  148. System.out.println("Press [enter] to send a message. Type 'exit' + [enter] to quit.");
  149. BufferedReader commandLine = new java.io.BufferedReader(new InputStreamReader(System.in));
  150. while (true) {
  151. String s = commandLine.readLine();
  152. if (s.equalsIgnoreCase("exit")) {
  153. simpleSenderReceiver.close();
  154. System.exit(0);
  155. } else {
  156. simpleSenderReceiver.sendMessage();
  157. }
  158. }
  159. } catch (Exception e) {
  160. e.printStackTrace();
  161. }
  162. }
  163. private void sendMessage() throws JMSException {
  164. TextMessage message = sendSession.createTextMessage();
  165. message.setText("Test AMQP message from JMS");
  166. long randomMessageID = randomGenerator.nextLong() >>>1;
  167. message.setJMSMessageID("ID:" + randomMessageID);
  168. sender.send(message);
  169. System.out.println("Sent message with JMSMessageID = " + message.getJMSMessageID());
  170. }
  171. public void close() throws JMSException {
  172. connection.close();
  173. }
  174. public void onMessage(Message message) {
  175. try {
  176. System.out.println("Received message with JMSMessageID = " + message.getJMSMessageID());
  177. message.acknowledge();
  178. } catch (Exception e) {
  179. e.printStackTrace();
  180. }
  181. }
  182. }
  183. ### Running the application
  184. Running the application produces output of the form:
  185. > java SimpleSenderReceiver
  186. Press [enter] to send a message. Type 'exit' + [enter] to quit.
  187. Sent message with JMSMessageID = ID:2867600614942270318
  188. Received message with JMSMessageID = ID:2867600614942270318
  189. Sent message with JMSMessageID = ID:7578408152750301483
  190. Received message with JMSMessageID = ID:7578408152750301483
  191. Sent message with JMSMessageID = ID:956102171969368961
  192. Received message with JMSMessageID = ID:956102171969368961
  193. exit
  194. ##Cross-platform messaging between JMS and .NET
  195. This guide showed how to send and receive messages to and from Service Bus using JMS. However, one of the key benefits of AMQP 1.0 is that it enables applications to be built from components written in different languages, with messages exchanged reliably and at full fidelity.
  196. Using the sample JMS application described above and a similar .NET application taken from a companion guide, [How to use AMQP 1.0 with the .NET Service Bus .NET API](http://aka.ms/lym3vk), you can exchange messages between .NET and Java.
  197. For more information about the details of cross-platform messaging using Service Bus and AMQP 1.0, see the [Service Bus AMQP 1.0 Developer's Guide](http://msdn.microsoft.com/en-us/library/windowsazure/jj841071.aspx).
  198. ### JMS to .NET
  199. To demonstrate JMS to .NET messaging:
  200. * Start the .NET sample application without any command-line arguments.
  201. * Start the Java sample application with the "sendonly" command-line argument. In this mode, the application will not receive messages from the queue, it will only send.
  202. * Press **Enter** a few times in the Java application console, which will cause messages to be sent.
  203. * These messages are received by the .NET application.
  204. <p><strong>Output from JMS application</strong></p>
  205. > java SimpleSenderReceiver sendonly
  206. Press [enter] to send a message. Type 'exit' + [enter] to quit.
  207. Sent message with JMSMessageID = ID:4364096528752411591
  208. Sent message with JMSMessageID = ID:459252991689389983
  209. Sent message with JMSMessageID = ID:1565011046230456854
  210. exit
  211. <p><strong>Output from .NET application</strong></p>
  212. > SimpleSenderReceiver.exe
  213. Press [enter] to send a message. Type 'exit' + [enter] to quit.
  214. Received message with MessageID = 4364096528752411591
  215. Received message with MessageID = 459252991689389983
  216. Received message with MessageID = 1565011046230456854
  217. exit
  218. ### .NET to JMS
  219. To demonstrate .NET to JMS messaging:
  220. * Start the .NET sample application with the "sendonly" command-line argument. In this mode, the application will not receive messages from the queue, it will only send.
  221. * Start the Java sample application without any command-line arguments.
  222. * Press **Enter** a few times in the .NET application console, which will cause messages to be sent.
  223. * These messages are received by the Java application.
  224. <p><strong>Output from .NET application</strong></p>
  225. > SimpleSenderReceiver.exe sendonly
  226. Press [enter] to send a message. Type 'exit' + [enter] to quit.
  227. Sent message with MessageID = d64e681a310a48a1ae0ce7b017bf1cf3
  228. Sent message with MessageID = 98a39664995b4f74b32e2a0ecccc46bb
  229. Sent message with MessageID = acbca67f03c346de9b7893026f97ddeb
  230. exit
  231. <p><strong>Output from JMS application</strong></p>
  232. > java SimpleSenderReceiver
  233. Press [enter] to send a message. Type 'exit' + [enter] to quit.
  234. Received message with JMSMessageID = ID:d64e681a310a48a1ae0ce7b017bf1cf3
  235. Received message with JMSMessageID = ID:98a39664995b4f74b32e2a0ecccc46bb
  236. Received message with JMSMessageID = ID:acbca67f03c346de9b7893026f97ddeb
  237. exit
  238. ##Unsupported features and restrictions
  239. The following restrictions exist when using JMS over AMQP 1.0 with Service Bus, namely:
  240. * Only one **MessageProducer** or **MessageConsumer** is allowed per **Session**. If you need to create multiple **MessageProducers** or **MessageConsumers** in an application, create a dedicated **Session** for each of them.
  241. * Volatile topic subscriptions are not currently supported.
  242. * **MessageSelectors** are not currently supported.
  243. * Temporary destinations, i.e., **TemporaryQueue**, **TemporaryTopic** are not currently supported, along with the **QueueRequestor** and **TopicRequestor** APIs that use them.
  244. * Transacted sessions and distributed transactions are not supported.
  245. ##Summary
  246. This how-to guide showed how to use Service Bus brokered messaging features (queues and publish/subscribe topics) from Java using the popular JMS API and AMQP 1.0.
  247. You can also use Service Bus AMQP 1.0 from other languages, including .NET, C, Python, and PHP. Components built using these different languages can exchange messages reliably and at full fidelity using the AMQP 1.0 support in Service Bus. For more information, see the [Service Bus AMQP 1.0 Developer's Guide](http://msdn.microsoft.com/en-us/library/windowsazure/jj841071.aspx).
  248. ##Further information
  249. * [AMQP 1.0 support in Azure Service Bus](http://aka.ms/pgr3dp)
  250. * [How to use AMQP 1.0 with the Service Bus .NET API](http://aka.ms/lym3vk)
  251. * [Service Bus AMQP 1.0 Developer's Guide](http://msdn.microsoft.com/en-us/library/windowsazure/jj841071.aspx)
  252. * [How to Use Service Bus Queues](http://www.windowsazure.com/en-us/develop/net/how-to-guides/service-bus-queues/)