| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| Architecture |
| --> |
| <html lang="en"> |
| <head> |
| <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> |
| <meta content="ActiveMQ's next generation of messaging" name="description"/> |
| <meta content="messaging,stomp,jms,activemq,apollo" name="keywords"/> |
| <meta content="Apollo" name="author"/> |
| <script src="../scripts/jquery.js"></script> |
| <link type="text/css" rel="stylesheet" href="../styles/impact/css/pygmentize.css"/> |
| <link type="text/css" rel="stylesheet" href="../styles/impact/css/site.css"/> |
| <title></title> |
| </head> |
| <body> |
| <div id="navigation"> |
| <div class="wrapper"> |
| <ul> |
| <li><a href="../index.html">Apollo 1.7.1</a></li> |
| <li><a href="../community/developers.html">Developers</a></li> |
| <li><a href="../community/index.html">Community</a></li> |
| <li><a href="../download.html">Download</a></li> |
| </ul> <div></div> |
| </div> |
| </div> |
| <div id="content"> |
| <div class="wrapper"> |
| <h1 id = "Apollo_1_7_1_OpenWire_Protocol_Manual">Apollo 1.7.1 OpenWire Protocol Manual</h1> |
| |
| <p><div class="toc"><ul style="list-style:none;"> |
| <li><a href="#Using_the_OpenWire_Protocol">Using the OpenWire Protocol</a></li> |
| <li><ul style="list-style:none;"> |
| <li><a href="#OpenWire_Protocol_Options">OpenWire Protocol Options</a></li> |
| <li><a href="#Protocol_Detection__different_that_open-wire_vesion_detection_">Protocol Detection (different that open-wire vesion detection)</a></li> |
| <li><a href="#Client_Libraries">Client Libraries</a></li> |
| <li><a href="#Broker_features_available_using_the_OpenWire_protocol">Broker features available using the OpenWire protocol</a></li> |
| <li><ul style="list-style:none;"> |
| <li><a href="#Destination_Types">Destination Types</a></li> |
| <li><a href="#Wildcard_Subscriptions">Wildcard Subscriptions</a></li> |
| <li><a href="#Composite_Destinations">Composite Destinations</a></li> |
| <li><a href="#Exclusive_Consumer">Exclusive Consumer</a></li> |
| <li><a href="#Temporary_Destinations">Temporary Destinations</a></li> |
| <li><a href="#Message_Selectors">Message Selectors</a></li> |
| <li><a href="#Browing_Subscription">Browing Subscription</a></li> |
| <li><a href="#Transactions">Transactions</a></li> |
| </ul></li> |
| <li><a href="#OpenWire_protocol_details">OpenWire protocol details</a></li> |
| <li><a href="#OpenWire_features_to_be_documented">OpenWire features to be documented</a></li> |
| <li><a href="#Unsupported_OpenWire_features:">Unsupported OpenWire features:</a></li> |
| </ul></li> |
| </ul></div></p> |
| |
| <h2 id = "Using_the_OpenWire_Protocol">Using the OpenWire Protocol</h2> |
| |
| <p>Clients can connect to Apollo using the |
| <a href="http://activemq.apache.org/openwire.html">OpenWire</a> protocol. OpenWire is a binary, |
| on-the-wire protocol used natively by <a href="http://activemq.apache.org/">ActiveMQ</a>. It was designed |
| to be a fast, full-featured, and JMS-compliant protocol for message brokers. Currently there are |
| native client libraries for Java, C, C#, and C++. Further OpenWire support can be built by |
| implementing language-specific code generators, however, for most cross-langauge needs, the |
| <a href="http://stomp.github.com">STOMP</a> protocol is best.</p> |
| |
| <p>OpenWire was designed to be extended but yet backward compatible with older versions. When a client connects |
| to the broker, the protocol version that's used is negotiated based on what each can support.</p> |
| |
| <h3 id = "OpenWire_Protocol_Options">OpenWire Protocol Options</h3> |
| |
| <p>You can use the <code>openwire</code> configuration element within the <code>connector</code> element |
| in the <code>apollo.xml</code> configuration file to change the default settings used |
| in the OpenWire protocol implementation.</p> |
| |
| <div class="syntax"><pre name='code' class='brush: xml; gutter: false;'><code> |
| <connector id="tcp" bind="tcp://0.0.0.0:61613"> |
| <openwire attribute="value"/> |
| </connector> |
| </code></pre></div> |
| |
| <p>The <code>openwire</code> element supports the following configuration attributes:</p> |
| |
| <ul> |
| <li><code>buffer_size</code> : How much each producer or subscription will buffer between |
| the client and the broker. Defaults to <code>640k</code>.</li> |
| <li><code>stack_trace</code> : If there is an exception on the broker, it will be sent back to the client. Default is <code>true</code></li> |
| <li><code>cache</code> : Used to reduce marshalling efforts within the broker. Cache data structures such as openwire commands, |
| destination objects, subscription info, etc. Default is <code>true</code></li> |
| <li><code>cache_size</code> : Number of internal data structures to cache. Default is <code>1024</code></li> |
| <li><code>tight_endcoding</code> : Optimize the encoding to be effecient over the wire at the expense of greater CPU usage to |
| marshal/unmarshal. Default is <code>true</code></li> |
| <li><code>tcp_no_delay</code> : Decide whether to use <a href="http://en.wikipedia.org/wiki/Nagle's_algorithm">Nagle's Algorithm</a> which improves TCP/IP effeciency for small packets. |
| Set to true to disable this algorithm. Default is <code>false</code> (which means nodelay is off, and it uses Nagle's algorithm)</li> |
| <li><code>max_inactivity_duration</code> : Max inactivity period, in milliseconds, at which point the socket would be considered |
| dead. Used by the heartbeat functionality. If there is a period of inactivity greater than this period, the socket will |
| be closed. Default is <code>30000</code></li> |
| <li><code>max_inactivity_duration_initial_delay</code> : Amount of time to delay between determining the socket should be closed |
| and actually closing it. Default is <code>30000</code></li> |
| <li><code>max_frame_size</code> : Size in bytes of the largest frame that can be sent to the broker. Default is <code>100MB</code></li> |
| <li><code>add_jmsxuserid</code> : If set to <code>false</code>, disables setting the JMSXUserID header on received messages. Default is <code>true</code>.</li> |
| </ul> |
| |
| <p>An example of configuring the OpenWire protocol</p> |
| |
| <div class="syntax"><pre name='code' class='brush: xml; gutter: false;'><code> |
| <connector id="tcp" bind="tcp://0.0.0.0:61613"> |
| <openwire tight_encoding="false" tcp_no_delay="true"/> |
| </connector> |
| </code></pre></div> |
| |
| <h3 id = "Protocol_Detection__different_that_open-wire_vesion_detection_">Protocol Detection (different that open-wire vesion detection)</h3> |
| |
| <p>Apollo was designed to be inherently multi-protocol. Although STOMP was the first protocol to be implemented in Apollo, the core |
| of the broker was not built around STOMP or any other specific protocol. Apollo, in fact by default, has the ability |
| to detect the protocol being used on the wire without further configuration. This makes the configuration easier on |
| the broker, and means you only need to open one connector that can handle multiple different types of wire protocols. |
| If you would like to specify a certain connector for OpenWire and another connector for a different protocol, you can |
| explicitly configure the connector to be an OpenWire connector:</p> |
| |
| <div class="syntax"><pre name='code' class='brush: xml; gutter: false;'><code> |
| <connector protocol="openwire" ... /> |
| </code></pre></div> |
| |
| <p>You can also support a limited subset of protocols:</p> |
| |
| <div class="syntax"><pre name='code' class='brush: xml; gutter: false;'><code> |
| <connector bind="..."> |
| <detect protocols="openwire stomp" /> |
| </connector> |
| </code></pre></div> |
| |
| <p>Or you can leave it open to any of the supported protocols (default), and the correct protocol will be used depending |
| on what the client is using. You do this by not specifying any protocol settings.</p> |
| |
| <p>Note, this type of on-the-wire protocol detection is different that the OpenWire version detection briefly mentioned |
| above. After the broker determines a client is using an OpenWire protocol, the version is negotiated separately from |
| how the broker determines a protocol.</p> |
| |
| <h3 id = "Client_Libraries">Client Libraries</h3> |
| |
| <p>To connect to Apollo using the OpenWire protocol, we recommend you use the latest <a href="http://activemq.apache.org/">ActiveMQ</a> 5.x client libraries.</p> |
| |
| <ul> |
| <li><a href="http://activemq.apache.org/c-integration.html">C</a></li> |
| <li><a href="http://activemq.apache.org/activemq-c-clients.html">C++</a></li> |
| <li><a href="http://activemq.apache.org/nms/">C# and .NET</a></li> |
| </ul> |
| |
| <p>To configure specific behaviors for your connection, see the <a href="http://activemq.apache.org/connection-configuration-uri.html">Connection reference</a> |
| for ActiveMQ 5.x</p> |
| |
| <h3 id = "Broker_features_available_using_the_OpenWire_protocol">Broker features available using the OpenWire protocol</h3> |
| |
| <h4 id = "Destination_Types">Destination Types</h4> |
| |
| <ul> |
| <li><p>Queues (for point-to-point messaging) - A JMS Queue implements load balancer semantics. A single message will be |
| received by exactly one consumer. If there are no consumers available at the time the message is sent it will be kept |
| until a consumer is available that can process the message. If a consumer receives a message and does not acknowledge |
| it before closing then the message will be redelivered to another consumer. A queue can have many consumers with |
| messages load balanced across the available consumers.</p></li> |
| <li><p>Topics (publish-subscribe) - In JMS a Topic implements publish and subscribe semantics. When you publish a message it |
| goes to all the subscribers who are interested - so zero to many subscribers will receive a copy of the message. Only |
| subscribers who had an active subscription at the time the broker receives the message will get a copy of the message.</p></li> |
| <li><p>Durable Subscriptions (persistent publish-subscribe) - Durable subscriptions allow you to achieve semantics similar to |
| a queue using topics. Specifically, this allows a subscription to subscribe and disconnect without worrying about losing messages. |
| If the client disconnects, the messages that arrive at the topic while the subscription is inactive will be queued up |
| for consumption when the subscription becomes reactivated.</p></li> |
| </ul> |
| |
| <h4 id = "Wildcard_Subscriptions">Wildcard Subscriptions</h4> |
| |
| <p>Wild cards can be used in destination names when subscribing as a consumer. This allows you to subscribe |
| to multiple destinations or hierarchy of destinations.</p> |
| |
| <ul> |
| <li><code>.</code> is used to separate names in a path</li> |
| <li><code>*</code> is used to match any name in a path</li> |
| <li><code>></code> is used to recursively match path names</li> |
| </ul> |
| |
| <p>Unlike some of the other protocols Apollo supports, for the OpenWire implementation, regex wildcards |
| are not supported. Also note that for other protocols, the wildcard for recursive destinations is indeed “>" and not |
| “**".</p> |
| |
| <h4 id = "Composite_Destinations">Composite Destinations</h4> |
| |
| <p>You can send to multiple destinations with one single operation. When you create a destination to which your producer |
| will be sending, you can specify multiple destinations with the “," (comma) destination separator. For example, |
| if you want to send a single message to two queues:</p> |
| |
| <pre><code>Destination destination = session.createQueue("test-queue,test-queue-foo") |
| MessageProducer producer = session.createProducer(destination); |
| TextMessage message = session.createTextMessage("Message #" + i); |
| producer.send(message);</code></pre> |
| |
| <p>Note both destinations named will be considered queues. However, you can also include a topic destination in your |
| list. You'll want to use the <code>topic://</code> prefix if mixing destination types (or <code>queue://</code> for queues):</p> |
| |
| <pre><code>Destination destination = session.createQueue("test-queue,test-queue-foo,topic://test-topic-foo")</code></pre> |
| |
| <p>Similarly you can consume from multiple destinations as well. When you set up your consumer's destination, just follow |
| the same rules as above.</p> |
| |
| <h4 id = "Exclusive_Consumer">Exclusive Consumer</h4> |
| |
| <p>To do exclusive consumer on a queue, you will specify the settings on the queue itself:</p> |
| |
| <pre><code>"QUEUE.NAME?consumer.exclusive=true"</code></pre> |
| |
| <p>The first consumer to subscribe to the queue will be the exclusive consumer. Any other consumers that |
| subscribe to the queue will not receive messages as long as the exclusive consumer is alive and consuming. If the |
| exclusive consumer goes away, the next in line to subscribe will be selected as the exclusive consumer. In general, |
| the order that's calculcated for who should be the next exclusive consumer is based on when they subscribe. The first |
| to subscribe wins and the others fall in line based on when they subscribed.</p> |
| |
| <h4 id = "Temporary_Destinations">Temporary Destinations</h4> |
| |
| <p>Temporary destinations are bound to the connection that created them; therefore, when the connection goes away, the |
| temporary destination will also go away. Using temporary is one way to implement a request-reply messaging pattern |
| with Apollo. The steps for using temporary queues or topics for request-reply are as follows:</p> |
| |
| <p>Create a temporary destination</p> |
| |
| <pre><code>Destination replyDest = session.createTemporaryQueue();</code></pre> |
| |
| <p>Create a consumer for that destination</p> |
| |
| <pre><code>MessageConsumer replyConsumer = session.createConsumer(replyDest);</code></pre> |
| |
| <p>Create a message to send as a request and set the JMSReplyTo header to the temp destination</p> |
| |
| <pre><code>message.setJMSReplyTo(replyDest);</code></pre> |
| |
| <p>Send the message. If the receiver of the message is aware that it's participating in a request-reply scenario, it |
| should place the response into the destination specified in the JMSReplyTo header.</p> |
| |
| <h4 id = "Message_Selectors">Message Selectors</h4> |
| |
| <p>You can use message selectors to create subscriptions to destinations that are filtered based on some headers or |
| properties in the message. You define a selector as a String that is similar to the SQL92 syntax.</p> |
| |
| <p>For example, to define a consumer on a destination that is only interested in messages that have a property named “intended” and |
| a value of “me”, pass a selector as the second argument to the <a href="http://docs.oracle.com/javaee/6/api/javax/jms/Session.html">session.createConsumer()</a> method:</p> |
| |
| <pre><code>session.createConsumer(destination, "intended = 'me'");</code></pre> |
| |
| <p>Now messages produced with a property/value combination specified in the selector will be delivered to the consumer.</p> |
| |
| <p>Here's an example of producing the message:</p> |
| |
| <div class="syntax"><pre name='code' class='brush: java; gutter: false;'><code> |
| MessageProducer producer = session.createProducer(destination); |
| |
| for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { |
| TextMessage message = session.createTextMessage("Message #" + i); |
| LOG.info("Sending message #" + i); |
| producer.send(message); |
| Thread.sleep(DELAY); |
| } |
| </code></pre></div> |
| |
| <h4 id = "Browing_Subscription">Browing Subscription</h4> |
| |
| <p>With a <a href="http://activemq.apache.org/maven/5.6.0/activemq-core/apidocs/org/apache/activemq/ActiveMQQueueBrowser.html">QueueBrowser</a>, you can |
| browse a queue's messages without actually consuming them. This can be useful for debugging, adding a user-interface layer, |
| or audit or logging.</p> |
| |
| <p>To establish a browsing subscription to a queue, use the JMS API:</p> |
| |
| <pre><code>QueueBrowser browser = session.createBrowser((Queue) destination);</code></pre> |
| |
| <p>Then you can enumerate the messages and examine them with the following idiom:</p> |
| |
| <pre><code>Enumeration enumeration = browser.getEnumeration(); |
| |
| while (enumeration.hasMoreElements()) { |
| TextMessage message = (TextMessage) enumeration.nextElement(); |
| System.out.println("Browsing: " + message); |
| }</code></pre> |
| |
| <p>When you browse a queue, only a snapshot of the queue will be available. If more messages are enqueued, the browsing |
| session will not automatically see those.</p> |
| |
| <p>Note, you cannot establish browsing sessions to a durable topic with OpenWire/JMS.</p> |
| |
| <h4 id = "Transactions">Transactions</h4> |
| |
| <p>Transactions can be done on both the consumer and the producer for any destination. When you create a session, |
| pass <code>true</code> to the first parameter:</p> |
| |
| <pre><code>Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);</code></pre> |
| |
| <p>You can <code>commit</code> or <code>rollback</code> a transaction by calling <code>session.commit()</code> or <code>session.rollback()</code> respectively. |
| On the broker side, each command that you take before calling <code>session.commit()</code> (like sending a message) gets batched |
| up in a TransactionContext. When commit is made, all of the commands are executed and a Response is sent to the client |
| (i.e., calling commit is a synchronous call. Before calling commit, all other commands are asyc).</p> |
| |
| <h3 id = "OpenWire_protocol_details">OpenWire protocol details</h3> |
| |
| <p>This section explains a little more about what's happening on the wire. The STOMP protocol, as it was designed, |
| is easy to understand and monitor since it's a text-based protocol. OpenWire, however, is binary, |
| and understanding the interactions that happen isn't as easy. Some clues might be helpful.</p> |
| |
| <p>All OpenWire commands are implemented as “command” objects following the Gang of Four <a href="http://en.wikipedia.org/wiki/Command_pattern">Command Pattern</a>. |
| The structure of the objects are described <a href="http://activemq.apache.org/openwire-version-2-specification.html">at the ActiveMQ website</a>, but |
| what about the interactions?</p> |
| |
| <p>Establishing a connection to the broker: |
| A connection is established between the client and the broker with the client creating a new ActiveMQConnection |
| (most likely using a connection factory of some sort). When a new “connection” is created, the underlying transport |
| mechanisms send a WireFormatInfo command to the broker. This command describes what version and configurations of the OpenWire protocol |
| the client wishes to use. For example, some of the configuration options are the ones listed above that can also be |
| configured on the broker.</p> |
| |
| <p>When the TCP connection is handled on the broker side, it sends a WireFormatInfo to the client. The purpose of exchanging |
| these WireFormatInfo commands is to be able to negotiate what settings to use as each the client and the server has |
| their own preferred settings. The lowest protocol version between the two is used. When the broker receives the client's |
| WireFormatInfo command, it negotiates the differences on its side and then sends a BrokerInfo command. Conversely |
| on the client, when it receives the broker's WireFormatInfo, it negotiates it and sends a ConnectionInfo command. When |
| the broker receives a ConnectionInfo command, it will either ack it with a Response command, or use security settings established globally |
| for the broker or for a given virtual host to determine whether connections are allowed. If a connection is not allowed |
| to the broker or to to virtual host, the broker will kill the connection.</p> |
| |
| <h3 id = "OpenWire_features_to_be_documented">OpenWire features to be documented</h3> |
| |
| <ul> |
| <li>Flow Control</li> |
| <li>Persistent Messaging</li> |
| <li>Message Expiration</li> |
| </ul> |
| |
| <h3 id = "Unsupported_OpenWire_features:">Unsupported OpenWire features:</h3> |
| |
| <p>You will get bad/undefined behaviour if you try to use any of the following OpenWire features:</p> |
| |
| <ul> |
| <li>XA transactions</li> |
| <li><a href="http://activemq.apache.org/message-groups.html">Message Groups using JMSXGroupID</a></li> |
| <li><a href="http://activemq.apache.org/retroactive-consumer.html">Subscription recovery/retroactive consumer</a></li> |
| <li><a href="http://activemq.apache.org/exclusive-consumer.html">Exclusive Consumer with Priority</a></li> |
| <li><a href="http://activemq.apache.org/virtual-destinations.html">Virtual Destinations</a></li> |
| </ul> |
| |
| <p>You can use Durable Subscriptions and/or <a href="user-manual.html#Mirrored_Queues">Mirrored Queues</a> to get |
| the same/similar behaviour that <a href="http://activemq.apache.org/virtual-destinations.html">Virtual Destinations</a> provide.</p> |
| |
| <!-- The following are not really OpenWire features.. but just general brokers features. |
| * [Network of brokers](http://activemq.apache.org/networks-of-brokers.html) |
| * [Shared-state Master/Slave](http://activemq.apache.org/shared-file-system-master-slave.html) |
| * [Startup Destinations](http://activemq.apache.org/configure-startup-destinations.html) |
| * [Delete inactive dests](http://activemq.apache.org/delete-inactive-destinations.html) |
| * [JMX](http://activemq.apache.org/jmx.html) |
| --> |
| <div></div> |
| </div> |
| </div> |
| </body> |
| </html> |