blob: 62f438a0b14d154de95f2d9c963d52d2f25c94de [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.18">
<link rel="icon" type="image/png" href="images/favicon.png">
<title>STOMP</title>
<link rel="stylesheet" href="css/asciidoctor.css">
<link rel="stylesheet" href="css/font-awesome.css">
<link rel="stylesheet" href="css/rouge-github.css">
</head>
<body class="book toc2 toc-left">
<div id="header">
<h1>STOMP</h1>
<div id="toc" class="toc2">
<div id="toctitle"><a href="index.html">User Manual for 2.32.0</a></div>
<ul class="sectlevel1">
<li><a href="#limitations">1. Limitations</a>
<ul class="sectlevel2">
<li><a href="#transactional-acknowledgements">1.1. Transactional Acknowledgements</a></li>
<li><a href="#virtual-hosting">1.2. Virtual Hosting</a></li>
</ul>
</li>
<li><a href="#mapping-stomp-destinations-to-addresses-and-queues">2. Mapping STOMP destinations to addresses and queues</a></li>
<li><a href="#logging">3. Logging</a></li>
<li><a href="#routing-semantics">4. Routing Semantics</a>
<ul class="sectlevel2">
<li><a href="#configuring-routing-semantics-from-the-client-side">4.1. Configuring Routing Semantics from the Client Side</a></li>
<li><a href="#configuring-routing-semantics-from-the-broker-side">4.2. Configuring Routing Semantics from the Broker side</a></li>
</ul>
</li>
<li><a href="#stomp-heart-beating-and-connection-ttl">5. STOMP heart-beating and connection-ttl</a></li>
<li><a href="#selectorfilter-expressions">6. Selector/Filter expressions</a></li>
<li><a href="#stomp-and-jms-interoperability">7. STOMP and JMS interoperability</a>
<ul class="sectlevel2">
<li><a href="#sending-and-consuming-stomp-message-from-jms-or-core-api">7.1. Sending and consuming STOMP message from JMS or Core API</a></li>
<li><a href="#message-ids-for-stomp-messages">7.2. Message IDs for STOMP messages</a></li>
</ul>
</li>
<li><a href="#durable-subscriptions">8. Durable Subscriptions</a></li>
<li><a href="#handling-of-large-messages-with-stomp">9. Handling of Large Messages with STOMP</a></li>
<li><a href="#web-sockets">10. Web Sockets</a></li>
<li><a href="#flow-control">11. Flow Control</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://stomp.github.io/">STOMP</a> is a text-orientated wire protocol that allows STOMP clients to communicate with STOMP Brokers.
Apache ActiveMQ Artemis supports STOMP 1.0, 1.1 and 1.2.</p>
</div>
<div class="paragraph">
<p>STOMP clients are available for several languages and platforms making it a good choice for interoperability.</p>
</div>
<div class="paragraph">
<p>By default there are <code>acceptor</code> elements configured to accept STOMP connections on ports <code>61616</code> and <code>61613</code>.</p>
</div>
<div class="paragraph">
<p>See the general <a href="protocols-interoperability.html#protocols-and-interoperability">Protocols and Interoperability</a> chapter for details on configuring an <code>acceptor</code> for STOMP.</p>
</div>
<div class="paragraph">
<p>Refer to the STOMP <a href="examples.html">examples</a> for a look at some of this functionality in action.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="limitations"><a class="anchor" href="#limitations"></a><a class="link" href="#limitations">1. Limitations</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="transactional-acknowledgements"><a class="anchor" href="#transactional-acknowledgements"></a><a class="link" href="#transactional-acknowledgements">1.1. Transactional Acknowledgements</a></h3>
<div class="paragraph">
<p>The STOMP specification identifies <strong>transactional acknowledgements</strong> as an optional feature.
Support for transactional acknowledgements is not implemented in Apache ActiveMQ Artemis.
The <code>ACK</code> frame can not be part of a transaction.
It will be ignored if its <code>transaction</code> header is set.</p>
</div>
</div>
<div class="sect2">
<h3 id="virtual-hosting"><a class="anchor" href="#virtual-hosting"></a><a class="link" href="#virtual-hosting">1.2. Virtual Hosting</a></h3>
<div class="paragraph">
<p>Apache ActiveMQ Artemis currently doesn&#8217;t support virtual hosting, which means the <code>host</code> header in <code>CONNECT</code> frame will be ignored.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="mapping-stomp-destinations-to-addresses-and-queues"><a class="anchor" href="#mapping-stomp-destinations-to-addresses-and-queues"></a><a class="link" href="#mapping-stomp-destinations-to-addresses-and-queues">2. Mapping STOMP destinations to addresses and queues</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>STOMP clients deals with <em>destinations</em> when sending messages and subscribing.
Destination names are simply strings which are mapped to some form of destination on the server - how the server translates these is left to the server implementation.</p>
</div>
<div class="paragraph">
<p>In Apache ActiveMQ Artemis, these destinations are mapped to <em>addresses</em> and <em>queues</em> depending on the operation being done and the desired semantics (e.g. anycast or multicast).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="logging"><a class="anchor" href="#logging"></a><a class="link" href="#logging">3. Logging</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Incoming and outgoing STOMP frames can be logged by enabling <code>DEBUG</code> for <code>org.apache.activemq.artemis.core.protocol.stomp.StompConnection</code>.
This can be extremely useful for debugging or simply monitoring client activity.
Along with the STOMP frame itself the remote IP address of the client is logged as well as the internal connection ID so that frames from the same client can be correlated.</p>
</div>
<div class="paragraph">
<p>Follow <a href="logging.html#configuring-a-specific-level-for-a-logger">these steps</a> to configure logging appropriately.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="routing-semantics"><a class="anchor" href="#routing-semantics"></a><a class="link" href="#routing-semantics">4. Routing Semantics</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The STOMP specification is intentionally ambiguous about message routing semantics.
When providing an overview of the protocol the STOMP 1.2 specification <a href="https://stomp.github.io/stomp-specification-1.2.html#Protocol_Overview">says</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="nowrap">A STOMP server is modelled as a set of destinations to which messages can be sent.
The STOMP protocol treats destinations as opaque string and their syntax is
server implementation specific. Additionally STOMP does not define what the
delivery semantics of destinations should be. The delivery, or
"message exchange", semantics of destinations can vary from server to server and
even from destination to destination. This allows servers to be creative with the
semantics that they can support with STOMP.</pre>
</div>
</div>
<div class="paragraph">
<p>Therefore, there are a handful of different ways to specify which semantics are desired both on the client-side and broker-side.</p>
</div>
<div class="sect2">
<h3 id="configuring-routing-semantics-from-the-client-side"><a class="anchor" href="#configuring-routing-semantics-from-the-client-side"></a><a class="link" href="#configuring-routing-semantics-from-the-client-side">4.1. Configuring Routing Semantics from the Client Side</a></h3>
<div class="sect3">
<h4 id="sending"><a class="anchor" href="#sending"></a><a class="link" href="#sending">4.1.1. Sending</a></h4>
<div class="paragraph">
<p>When a STOMP client sends a message (using a <code>SEND</code> frame), the protocol manager looks at the <code>destination-type</code> header to determine where to route it and potentially how to create the address and/or queue to which it is being sent.
Valid values are <code>ANYCAST</code> and <code>MULTICAST</code> (case sensitive).
If no indication of routing type is supplied (either by the client or the broker) then the default defined in the corresponding <code>default-address-routing-type</code> &amp; <code>default-queue-routing-type</code> address-settings will be used as necessary.</p>
</div>
<div class="paragraph">
<p>The <code>destination</code> header maps to an address of the same name if <code>MULTICAST</code> is used and additionally to a queue of the same name if <code>ANYCAST</code> is used.</p>
</div>
</div>
<div class="sect3">
<h4 id="subscribing"><a class="anchor" href="#subscribing"></a><a class="link" href="#subscribing">4.1.2. Subscribing</a></h4>
<div class="paragraph">
<p>When a STOMP client subscribes to a destination (using a <code>SUBSCRIBE</code> frame), the protocol manager looks at the <code>subscription-type</code> header frame to determine what subscription semantics to use and potentially how to create the address and/or queue for the subscription.
If no indication of routing type is supplied (either by the client or the broker) then the default defined in the corresponding <code>default-address-routing-type</code> &amp; <code>default-queue-routing-type</code> address-settings will be used as necessary.</p>
</div>
<div class="paragraph">
<p>The <code>destination</code> header maps to an address of the same name if <code>MULTICAST</code> is used and additionally to a queue of the same name if <code>ANYCAST</code> is used.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="configuring-routing-semantics-from-the-broker-side"><a class="anchor" href="#configuring-routing-semantics-from-the-broker-side"></a><a class="link" href="#configuring-routing-semantics-from-the-broker-side">4.2. Configuring Routing Semantics from the Broker side</a></h3>
<div class="paragraph">
<p>On the broker-side there are two main options for specifying routing semantics - prefixes and address settings</p>
</div>
<div class="sect3">
<h4 id="prefixes"><a class="anchor" href="#prefixes"></a><a class="link" href="#prefixes">4.2.1. Prefixes</a></h4>
<div class="paragraph">
<p>Using prefixes involves specifying the <code>anycastPrefix</code> and/or the <code>multicastPrefix</code> on the acceptor which the STOMP client is using.
For the STOMP use-case these prefixes tell the broker that destinations using them should be treated as anycast or multicast.
For example, if the acceptor has <code>anycastPrefix=queue/</code> then when a STOMP client sends a message to <code>destination:queue/foo</code> the broker will auto-create the address <code>foo</code> and queue <code>foo</code> appropriately as anycast and the message will be placed in that queue.
Additionally, if the acceptor has <code>multicastPrefix=topic/</code> then when a STOMP client sends a message to <code>destination:topic/bar</code> the broker will auto-create the address bar as multicast, but it won&#8217;t create a queue since multicast (i.e. pub/sub) semantics require a client to explicitly create a subscription to receive those messages.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The <code>anycastPrefix</code> and/or <code>multicastPrefix</code> on the acceptor will be stripped from the <code>destination</code> value.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="address-settings"><a class="anchor" href="#address-settings"></a><a class="link" href="#address-settings">4.2.2. Address Settings</a></h4>
<div class="paragraph">
<p>Using address settings involves defining address-setting elements whose <code>match</code> corresponds with the destination names the clients will use along with the proper <code>delimiter</code> to enabled matching.
For example, broker.xml could use the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;address-settings&gt;</span>
<span class="nt">&lt;address-setting</span> <span class="na">match=</span><span class="s">"queue/#"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-address-routing-type&gt;</span>ANYCAST<span class="nt">&lt;/default-address-routing-type&gt;</span>
<span class="nt">&lt;default-queue-routing-type&gt;</span>ANYCAST<span class="nt">&lt;/default-queue-routing-type&gt;</span>
<span class="nt">&lt;/address&gt;</span>
<span class="nt">&lt;address-setting</span> <span class="na">match=</span><span class="s">"topic/#"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-address-routing-type&gt;</span>MULTICAST<span class="nt">&lt;/default-address-routing-type&gt;</span>
<span class="nt">&lt;default-queue-routing-type&gt;</span>MULTICAST<span class="nt">&lt;/default-queue-routing-type&gt;</span>
<span class="nt">&lt;/address&gt;</span>
<span class="nt">&lt;/address-settings&gt;</span>
<span class="nt">&lt;wildcard-addresses&gt;</span>
<span class="nt">&lt;delimiter&gt;</span>/<span class="nt">&lt;/delimiter&gt;</span>
<span class="nt">&lt;/wildcard-addresses&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then if a STOMP client sends a message to <code>destination:queue/foo</code> the broker will auto-create the address <code>queue/foo</code> and queue <code>queue/foo</code> appropriately as anycast and the message will be placed in that queue.
Additionally, if a STOMP client sends a message to <code>destination:topic/bar</code> the broker will auto-create the address <code>topic/bar</code> as multicast, but it won&#8217;t create a queue as previously explained.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="stomp-heart-beating-and-connection-ttl"><a class="anchor" href="#stomp-heart-beating-and-connection-ttl"></a><a class="link" href="#stomp-heart-beating-and-connection-ttl">5. STOMP heart-beating and connection-ttl</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Well behaved STOMP clients will always send a <code>DISCONNECT</code> frame before closing their connections.
In this case the server will clear up any server side resources such as sessions and consumers synchronously.
However if STOMP clients exit without sending a <code>DISCONNECT</code> frame or if they crash the server will have no way of knowing immediately whether the client is still alive or not.
STOMP connections therefore default to a <code>connection-ttl</code> value of 1 minute (see chapter on <a href="connection-ttl.html#detecting-dead-connections">connection-ttl</a> for more information.
This value can be overridden using the <code>connection-ttl-override</code> property or if you need a specific connectionTtl for your stomp connections without affecting the broker-wide <code>connection-ttl-override</code> setting, you can configure your stomp acceptor with the <code>connectionTtl</code> property, which is used to set the ttl for connections that are created from that acceptor.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;acceptor</span> <span class="na">name=</span><span class="s">"stomp-acceptor"</span><span class="nt">&gt;</span>tcp://localhost:61613?protocols=STOMP;connectionTtl=20000<span class="nt">&lt;/acceptor&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The above configuration will make sure that any STOMP connection that is created from that acceptor and does not include a <code>heart-beat</code> header or disables client-to-server heart-beats by specifying a <code>0</code> value will have its <code>connection-ttl</code> set to 20 seconds.
The <code>connectionTtl</code> set on an acceptor will take precedence over <code>connection-ttl-override</code>.
The default <code>connectionTtl</code> is 60,000 milliseconds.</p>
</div>
<div class="paragraph">
<p>Since STOMP 1.0 does not support heart-beating then all connections from STOMP 1.0 clients will have a connection TTL imposed upon them by the broker based on the aforementioned configuration options.
Likewise, any STOMP 1.1 or 1.2 clients that don&#8217;t specify a <code>heart-beat</code> header or disable client-to-server heart-beating (e.g. by sending <code>0,X</code> in the <code>heart-beat</code> header) will have a connection TTL imposed upon them by the broker.</p>
</div>
<div class="paragraph">
<p>For STOMP 1.1 and 1.2 clients which send a non-zero client-to-server <code>heart-beat</code> header value then their connection TTL will be set accordingly.
However, the broker will not strictly set the connection TTL to the same value as the specified in the <code>heart-beat</code> since even small network delays could then cause spurious disconnects.
Instead, the client-to-server value in the <code>heart-beat</code> will be multiplied by the <code>heartBeatToConnectionTtlModifier</code> specified on the acceptor.
The <code>heartBeatToConnectionTtlModifier</code> is a decimal value that defaults to <code>2.0</code> so for example, if a client sends a <code>heart-beat</code> header of <code>1000,0</code> the connection TTL will be set to <code>2000</code> so that the data or ping frames sent every 1000 milliseconds will have a sufficient cushion so as not to be considered late and trigger a disconnect.
This is also in accordance with the STOMP 1.1 and 1.2 specifications which both state, "because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin."</p>
</div>
<div class="paragraph">
<p>The minimum and maximum connection TTL allowed can also be specified on the acceptor via the <code>connectionTtlMin</code> and <code>connectionTtlMax</code> properties respectively.
The default <code>connectionTtlMin</code> is 1000 and the default <code>connectionTtlMax</code> is Java&#8217;s <code>Long.MAX_VALUE</code> meaning there essentially is no max connection TTL by default.
Keep in mind that the <code>heartBeatToConnectionTtlModifier</code> is relevant here.
For example, if a client sends a <code>heart-beat</code> header of <code>20000,0</code> and the acceptor is using a <code>connectionTtlMax</code> of <code>30000</code> and a default <code>heartBeatToConnectionTtlModifier</code> of <code>2.0</code> then the connection TTL would be <code>40000</code> (i.e. <code>20000</code> * <code>2.0</code>) which would exceed the <code>connectionTtlMax</code>.
In this case the server would respond to the client with a <code>heart-beat</code> header of <code>0,15000</code> (i.e. <code>30000</code> / <code>2.0</code>).
As described previously, this is to make sure there is a sufficient cushion for the client heart-beats in accordance with the STOMP 1.1 and 1.2 specifications.
The same kind of calculation is done for <code>connectionTtlMin</code>.</p>
</div>
<div class="paragraph">
<p>The minimum server-to-client heart-beat value is 500ms.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Please note that the STOMP protocol version 1.0 does not contain any heart-beat frame.
It is therefore the user&#8217;s responsibility to make sure data is sent within connection-ttl or the server will assume the client is dead and clean up server side resources.
With STOMP 1.1 users can use heart-beats to maintain the life cycle of stomp connections.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="selectorfilter-expressions"><a class="anchor" href="#selectorfilter-expressions"></a><a class="link" href="#selectorfilter-expressions">6. Selector/Filter expressions</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>STOMP subscribers can specify an expression used to select or filter what the subscriber receives using the <code>selector</code> header.
The filter expression syntax follows the <em>core filter syntax</em> described in the <a href="filter-expressions.html#filter-expressions">Filter Expressions</a> documentation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="stomp-and-jms-interoperability"><a class="anchor" href="#stomp-and-jms-interoperability"></a><a class="link" href="#stomp-and-jms-interoperability">7. STOMP and JMS interoperability</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="sending-and-consuming-stomp-message-from-jms-or-core-api"><a class="anchor" href="#sending-and-consuming-stomp-message-from-jms-or-core-api"></a><a class="link" href="#sending-and-consuming-stomp-message-from-jms-or-core-api">7.1. Sending and consuming STOMP message from JMS or Core API</a></h3>
<div class="paragraph">
<p>STOMP is mainly a text-orientated protocol.
To make it simpler to interoperate with JMS and Core API, our STOMP implementation checks for presence of the <code>content-length</code> header to decide how to map a STOMP 1.0 message to a JMS Message or a Core message.</p>
</div>
<div class="paragraph">
<p>If the STOMP 1.0 message does <em>not</em> have a <code>content-length</code> header, it will be mapped to a JMS <em>TextMessage</em> or a Core message with a <em>single nullable SimpleString in the body buffer</em>.</p>
</div>
<div class="paragraph">
<p>Alternatively, if the STOMP 1.0 message <em>has</em> a <code>content-length</code> header, it will be mapped to a JMS <em>BytesMessage</em> or a Core message with a <em>byte[] in the body buffer</em>.</p>
</div>
<div class="paragraph">
<p>The same logic applies when mapping a JMS message or a Core message to STOMP.
A STOMP 1.0 client can check the presence of the <code>content-length</code> header to determine the type of the message body (String or bytes).</p>
</div>
</div>
<div class="sect2">
<h3 id="message-ids-for-stomp-messages"><a class="anchor" href="#message-ids-for-stomp-messages"></a><a class="link" href="#message-ids-for-stomp-messages">7.2. Message IDs for STOMP messages</a></h3>
<div class="paragraph">
<p>When receiving STOMP messages via a JMS consumer or a QueueBrowser, the messages have no properties like JMSMessageID by default.
However this may bring some inconvenience to clients who wants an ID for their purpose.
The broker STOMP provides a parameter to enable message ID on each incoming STOMP message.
If you want each STOMP message to have a unique ID, just set the <code>stompEnableMessageId</code> to true.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;acceptor</span> <span class="na">name=</span><span class="s">"stomp-acceptor"</span><span class="nt">&gt;</span>tcp://localhost:61613?protocols=STOMP;stompEnableMessageId=true<span class="nt">&lt;/acceptor&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>When the server starts with the above setting, each stomp message sent through this acceptor will have an extra property added.
The property key is <code>amqMessageId</code> and the value is a String representation of a long type internal message id prefixed with <code>STOMP</code>, like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="nowrap">amqMessageId : STOMP12345</pre>
</div>
</div>
<div class="paragraph">
<p>The default <code>stompEnableMessageId</code> value is <code>false</code>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="durable-subscriptions"><a class="anchor" href="#durable-subscriptions"></a><a class="link" href="#durable-subscriptions">8. Durable Subscriptions</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>SUBSCRIBE</code> and <code>UNSUBSCRIBE</code> frames can be augmented with special headers to create and destroy durable subscriptions respectively.</p>
</div>
<div class="paragraph">
<p>To create a durable subscription the <code>client-id</code> header must be set on the <code>CONNECT</code> frame and the <code>durable-subscription-name</code> must be set on the <code>SUBSCRIBE</code> frame.
The combination of these two headers will form the identity of the durable subscription.</p>
</div>
<div class="paragraph">
<p>To delete a durable subscription the <code>client-id</code> header must be set on the <code>CONNECT</code> frame and the <code>durable-subscription-name</code> must be set on the <code>UNSUBSCRIBE</code> frame.
The values for these headers should match what was set on the <code>SUBSCRIBE</code> frame to delete the corresponding durable subscription.</p>
</div>
<div class="paragraph">
<p>Aside from <code>durable-subscription-name</code>, the broker also supports <code>durable-subscriber-name</code> (a deprecated property used before <code>durable-subscription-name</code>) as well as <code>activemq.subscriptionName</code> from ActiveMQ "Classic".
This is the order of precedence if the frame contains more than one of these:</p>
</div>
<div class="paragraph">
<p>1) <code>durable-subscriber-name</code> 2) <code>durable-subscription-name</code> 3) <code>activemq.subscriptionName</code></p>
</div>
<div class="paragraph">
<p>It is possible to pre-configure durable subscriptions since the STOMP implementation creates the queue used for the durable subscription in a deterministic way (i.e. using the format of <code>client-id</code>.<code>subscription-name</code>).
For example, if you wanted to configure a durable subscription on the address <code>myAddress</code> with a client-id of <code>myclientid</code> and a subscription name of <code>mysubscription</code> then configure the durable subscription:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;addresses&gt;</span>
<span class="nt">&lt;address</span> <span class="na">name=</span><span class="s">"myAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;multicast&gt;</span>
<span class="nt">&lt;queue</span> <span class="na">name=</span><span class="s">"myclientid.mysubscription"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/multicast&gt;</span>
<span class="nt">&lt;/address&gt;</span>
<span class="nt">&lt;/addresses&gt;</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="handling-of-large-messages-with-stomp"><a class="anchor" href="#handling-of-large-messages-with-stomp"></a><a class="link" href="#handling-of-large-messages-with-stomp">9. Handling of Large Messages with STOMP</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>STOMP clients may send very large frame bodies which can exceed the size of the broker&#8217;s internal buffer, causing unexpected errors.
To prevent this situation from happening, the broker provides a STOMP configuration attribute <code>stompMinLargeMessageSize</code>.
This attribute can be configured inside a stomp acceptor, as a parameter.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;acceptor</span> <span class="na">name=</span><span class="s">"stomp-acceptor"</span><span class="nt">&gt;</span>tcp://localhost:61613?protocols=STOMP;stompMinLargeMessageSize=10240<span class="nt">&lt;/acceptor&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The type of this attribute is integer.
When this attributed is configured, the broker will check the size of the body of each STOMP frame arrived from connections established with this acceptor.
If the size of the body is equal or greater than the value of <code>stompMinLargeMessageSize</code>, the message will be persisted as a large message.
When a large message is delivered to a STOMP consumer, the broker will automatically handle the conversion from a large message to a normal message, before sending it to the client.</p>
</div>
<div class="paragraph">
<p>If a large message is compressed, the server will uncompressed it before sending it to stomp clients.
The default value of <code>stompMinLargeMessageSize</code> is the same as the default value of <a href="large-messages.html#configuring-the-core-client">minLargeMessageSize</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="web-sockets"><a class="anchor" href="#web-sockets"></a><a class="link" href="#web-sockets">10. Web Sockets</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Apache ActiveMQ Artemis also supports STOMP over <a href="https://html.spec.whatwg.org/multipage/web-sockets.html">Web Sockets</a>.
Modern web browsers which support Web Sockets can send and receive STOMP messages.</p>
</div>
<div class="paragraph">
<p>STOMP over Web Sockets is supported via the normal STOMP acceptor:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="xml"><span class="nt">&lt;acceptor</span> <span class="na">name=</span><span class="s">"stomp-ws-acceptor"</span><span class="nt">&gt;</span>tcp://localhost:61614?protocols=STOMP<span class="nt">&lt;/acceptor&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>With this configuration, Apache ActiveMQ Artemis will accept STOMP connections over Web Sockets on the port <code>61614</code>.
Web browsers can then connect to <code>ws://&lt;server&gt;:61614</code> using a Web Socket to send and receive STOMP messages.</p>
</div>
<div class="paragraph">
<p>A companion JavaScript library to ease client-side development is available from <a href="https://github.com/jmesnil/stomp-websocket">GitHub</a> (please see its <a href="http://jmesnil.net/stomp-websocket/doc/">documentation</a> for a complete description).</p>
</div>
<div class="paragraph">
<p>The payload length of Web Socket frames can vary between client implementations.
By default the broker will accept frames with a payload length of 65,536.
If the client needs to send payloads longer than this in a single frame this length can be adjusted by using the <code>webSocketMaxFramePayloadLength</code> URL parameter on the acceptor.
In previous version this was configured via the similarly named <code>stompMaxFramePayloadLength</code> acceptor URL parameter.</p>
</div>
<div class="paragraph">
<p>Web Socket frames can be encoded as either <a href="https://datatracker.ietf.org/doc/html/rfc6455#section-11.8">binary or text</a>.
By default the broker encodes them as binary.
However, this can be changed by using the <code>webSocketEncoderType</code> acceptor URL parameter.
Valid values are <code>binary</code> and <code>text</code>.</p>
</div>
<div class="paragraph">
<p>The <code>stomp-websockets</code> <a href="examples.html">example</a> shows how to configure an Apache ActiveMQ Artemis broker to have web browsers and Java applications exchanges messages.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="flow-control"><a class="anchor" href="#flow-control"></a><a class="link" href="#flow-control">11. Flow Control</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>STOMP clients can use the <code>consumer-window-size</code> header on the <code>SUBSCRIBE</code> frame to control the flow of messages to clients.
This is broadly discussed in the <a href="flow-control.html#flow-control">Flow Control</a> chapter.</p>
</div>
<div class="paragraph">
<p>This ability is similar to the <code>activemq.prefetchSize</code> header supported by ActiveMQ "Classic".
However, that header specifies the size in terms of <em>messages</em> whereas <code>consumer-window-size</code> specifies the size in terms of <em>bytes</em>.
ActiveMQ Artemis supports the <code>activemq.prefetchSize</code> header for backwards compatibility but the value will be interpreted as <em>bytes</em> just like <code>consumer-window-size</code> would be.
If both <code>activemq.prefetchSize</code> and <code>consumer-window-size</code> are set then the value for <code>consumer-window-size</code> will be used.</p>
</div>
<div class="paragraph">
<p>Setting <code>consumer-window-size</code> to <code>0</code> will ensure that once a STOMP client receives a message that it will <em>not</em> receive another one until it sends the appropriate <code>ACK</code> or <code>NACK</code> frame for the message it already has.</p>
</div>
<div class="paragraph">
<p>Setting <code>consumer-window-size</code> to a value <em>greater than</em> <code>0</code> will allow it to receive messages until the cumulative bytes of those messages reaches the configured size.
Once that happens the client will not receive any more messages until it sends the appropriate <code>ACK</code> or <code>NACK</code> frame for the messages it already has.</p>
</div>
<div class="paragraph">
<p>Setting <code>consumer-window-size</code> to <code>-1</code> means there is no flow control and the broker will dispatch messages to clients as fast as it can.</p>
</div>
<div class="paragraph">
<p>Flow control can be configured at the <code>acceptor</code> as well using the <code>stompConsumerWindowSize</code> URL parameter.
This value is <code>10240</code> (i.e. 10K) by default for clients using <code>client</code> and <code>client-individual</code> acknowledgement modes.
It is <code>-1</code> for clients using the <code>auto</code> acknowledgement mode.
Even if <code>stompConsumerWindowSize</code> is set on the STOMP <code>acceptor</code> it will be overriden by the value provided by individual clients using the <code>consumer-window-size</code> header on their <code>SUBSCRIBE</code> frame.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The <code>stompConsumerWindowSize</code> URL parameter used to be called <code>stompConsumerCredits</code> but was changed to be more consistent with the new header name (i.e. <code>consumer-window-size</code>).
The <code>stompConsumerCredits</code> parameter is deprecated but it will still work for the time being.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Using the <a href="#logging">DEBUG logging</a> mentioned earlier it is possible to see the size of the <code>MESSAGE</code> frames dispatched to clients.
This can help when trying to determine the best <code>consumer-window-size</code> setting.</p>
</div>
</div>
</div>
</div>
</body>
</html>