blob: 9871f6c7037a1f83439f6d8a9b0a441ac8f6615f [file] [log] [blame]
<!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>
&lt;connector id=&quot;tcp&quot; bind=&quot;tcp://0.0.0.0:61613&quot;&gt;
&lt;openwire attribute=&quot;value&quot;/&gt;
&lt;/connector&gt;
</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&#95;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>
&lt;connector id=&quot;tcp&quot; bind=&quot;tcp://0.0.0.0:61613&quot;&gt;
&lt;openwire tight_encoding=&quot;false&quot; tcp_no_delay=&quot;true&quot;/&gt;
&lt;/connector&gt;
</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>
&lt;connector protocol=&quot;openwire&quot; ... /&gt;
</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>
&lt;connector bind=&quot;...&quot;&gt;
&lt;detect protocols=&quot;openwire stomp&quot; /&gt;
&lt;/connector&gt;
</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>&gt;</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 &ldquo;>" and not
&ldquo;**".</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 &ldquo;," (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 &ldquo;intended&rdquo; and
a value of &ldquo;me&rdquo;, 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 &lt; NUM_MESSAGES_TO_SEND; i++) {
TextMessage message = session.createTextMessage(&quot;Message #&quot; + i);
LOG.info(&quot;Sending message #&quot; + 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 &ldquo;command&rdquo; objects following the Gang of Four <a href="http://en.wikipedia.org/wiki/Command&#95;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 &ldquo;connection&rdquo; 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&#95;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>