308 lines
20 KiB
XML
308 lines
20 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!-- ============================================================================= -->
|
||
<!-- Copyright © 2009 Red Hat, Inc. and others. -->
|
||
<!-- -->
|
||
<!-- The text of and illustrations in this document are licensed by Red Hat under -->
|
||
<!-- a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). -->
|
||
<!-- -->
|
||
<!-- An explanation of CC-BY-SA is available at -->
|
||
<!-- -->
|
||
<!-- http://creativecommons.org/licenses/by-sa/3.0/. -->
|
||
<!-- -->
|
||
<!-- In accordance with CC-BY-SA, if you distribute this document or an adaptation -->
|
||
<!-- of it, you must provide the URL for the original version. -->
|
||
<!-- -->
|
||
<!-- Red Hat, as the licensor of this document, waives the right to enforce, -->
|
||
<!-- and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent -->
|
||
<!-- permitted by applicable law. -->
|
||
<!-- ============================================================================= -->
|
||
|
||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||
<!ENTITY % BOOK_ENTITIES SYSTEM "ActiveMQ_User_Manual.ent">
|
||
%BOOK_ENTITIES;
|
||
]>
|
||
<chapter id="interoperability">
|
||
<title>Interoperability</title>
|
||
<section id="stomp">
|
||
<title>Stomp</title>
|
||
<para><ulink url="http://stomp.github.com/">Stomp</ulink> is a text-orientated wire protocol that allows
|
||
Stomp clients to communicate with Stomp Brokers. ActiveMQ now supports Stomp 1.0, 1.1 and 1.2.</para>
|
||
<para>Stomp clients are available for
|
||
several languages and platforms making it a good choice for interoperability.</para>
|
||
<section id="stomp.native">
|
||
<title>Native Stomp support</title>
|
||
<para>ActiveMQ provides native support for Stomp. To be able to send and receive Stomp messages,
|
||
you must configure a <literal>NettyAcceptor</literal> with a <literal>protocols</literal>
|
||
parameter set to have <literal>stomp</literal>:</para>
|
||
<programlisting>
|
||
<acceptor name="stomp-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="STOMP"/>
|
||
<param key="port" value="61613"/>
|
||
</acceptor></programlisting>
|
||
<para>With this configuration, ActiveMQ will accept Stomp connections on
|
||
the port <literal>61613</literal> (which is the default port of the Stomp brokers).</para>
|
||
<para>See the <literal>stomp</literal> example which shows how to configure a ActiveMQ server with Stomp.</para>
|
||
<section>
|
||
<title>Limitations</title>
|
||
<para>Message acknowledgements are not transactional. The ACK frame can not be part of a transaction
|
||
(it will be ignored if its <literal>transaction</literal> header is set).</para>
|
||
</section>
|
||
<section>
|
||
<title>Stomp 1.1/1.2 Notes</title>
|
||
<section>
|
||
<title>Virtual Hosting</title>
|
||
<para>ActiveMQ currently doesn't support virtual hosting, which means the 'host' header
|
||
in CONNECT fram will be ignored.</para>
|
||
</section>
|
||
<section>
|
||
<title>Heart-beating</title>
|
||
<para>ActiveMQ specifies a minimum value for both client and server heart-beat intervals.
|
||
The minimum interval for both client and server heartbeats is 500 milliseconds. That means if
|
||
a client sends a CONNECT frame with heartbeat values lower than 500, the server will defaults
|
||
the value to 500 milliseconds regardless the values of the 'heart-beat' header in the frame.</para>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Mapping Stomp destinations to ActiveMQ addresses and queues</title>
|
||
<para>Stomp clients deals with <emphasis>destinations</emphasis> 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.</para>
|
||
<para>In ActiveMQ, these destinations are mapped to <emphasis>addresses</emphasis> and <emphasis>queues</emphasis>.
|
||
When a Stomp client sends a message (using a <literal>SEND</literal> frame), the specified destination is mapped
|
||
to an address.
|
||
When a Stomp client subscribes (or unsubscribes) for a destination (using a <literal>SUBSCRIBE</literal>
|
||
or <literal>UNSUBSCRIBE</literal> frame), the destination is mapped to a ActiveMQ queue.</para>
|
||
</section>
|
||
<section>
|
||
<title>STOMP and connection-ttl</title>
|
||
<para>Well behaved STOMP clients will always send a DISCONNECT 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 DISCONNECT 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 connection-ttl value of 1 minute (see chapter on <link linkend="connection-ttl"
|
||
>connection-ttl</link> for more information. This value can be overridden using connection-ttl-override.
|
||
</para>
|
||
<para>If you need a specific connection-ttl for your stomp connections without affecting the connection-ttl-override setting, you
|
||
can configure your stomp acceptor with the "connection-ttl" property, which is used to set the ttl for connections that are
|
||
created from that acceptor. For example:
|
||
</para>
|
||
<programlisting>
|
||
<acceptor name="stomp-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="STOMP"/>
|
||
<param key="port" value="61613"/>
|
||
<param key="connection-ttl" value="20000"/>
|
||
</acceptor></programlisting>
|
||
<para>The above configuration will make sure that any stomp connection that is created from that acceptor will have its
|
||
connection-ttl set to 20 seconds.</para>
|
||
|
||
<note><para>Please note that the STOMP protocol version 1.0 does not contain any heartbeat frame. It is therefore the user'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 <literal>Stomp 1.1</literal> users can use heart-beats to maintain the life cycle of stomp
|
||
connections.</para></note>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Stomp and JMS interoperability</title>
|
||
<section>
|
||
<title>Using JMS destinations</title>
|
||
<para>As explained in <xref linkend="jms-core-mapping" />, JMS destinations are also mapped to ActiveMQ addresses and queues.
|
||
If you want to use Stomp to send messages to JMS destinations, the Stomp destinations must follow the same convention:</para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>send or subscribe to a JMS <emphasis>Queue</emphasis> by prepending the queue name by <literal>jms.queue.</literal>.</para>
|
||
<para>For example, to send a message to the <literal>orders</literal> JMS Queue, the Stomp client must send the frame:</para>
|
||
<programlisting>
|
||
SEND
|
||
destination:jms.queue.orders
|
||
|
||
hello queue orders
|
||
^@</programlisting>
|
||
</listitem>
|
||
<listitem>
|
||
<para>send or subscribe to a JMS <emphasis>Topic</emphasis> by prepending the topic name by <literal>jms.topic.</literal>.</para>
|
||
<para>For example to subscribe to the <literal>stocks</literal> JMS Topic, the Stomp client must send the frame:</para>
|
||
<programlisting>
|
||
SUBSCRIBE
|
||
destination:jms.topic.stocks
|
||
|
||
^@</programlisting>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Sending and consuming Stomp message from JMS or ActiveMQ Core API</title>
|
||
<para>Stomp is mainly a text-orientated protocol. To make it simpler to interoperate with JMS and ActiveMQ Core API,
|
||
our Stomp implementation checks for presence of the <literal>content-length</literal> header to decide how to map a Stomp message
|
||
to a JMS Message or a Core message.
|
||
</para>
|
||
<para>If the Stomp message does <emphasis>not</emphasis> have a <literal>content-length</literal> header, it will be mapped to a JMS <emphasis>TextMessage</emphasis>
|
||
or a Core message with a <emphasis>single nullable SimpleString in the body buffer</emphasis>.</para>
|
||
<para>Alternatively, if the Stomp message <emphasis>has</emphasis> a <literal>content-length</literal> header,
|
||
it will be mapped to a JMS <emphasis>BytesMessage</emphasis>
|
||
or a Core message with a <emphasis>byte[] in the body buffer</emphasis>.</para>
|
||
<para>The same logic applies when mapping a JMS message or a Core message to Stomp. A Stomp client can check the presence
|
||
of the <literal>content-length</literal> header to determine the type of the message body (String or bytes).</para>
|
||
</section>
|
||
<section>
|
||
<title>Message IDs for Stomp messages</title>
|
||
<para>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. ActiveMQ 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 <literal>stomp-enable-message-id</literal> to true. For example:</para>
|
||
<programlisting>
|
||
<acceptor name="stomp-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="STOMP"/>
|
||
<param key="port" value="61613"/>
|
||
<param key="stomp-enable-message-id" value="true"/>
|
||
</acceptor></programlisting>
|
||
<para>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 <literal>
|
||
hq-message-id</literal> and the value is a String representation of a long type internal
|
||
message id prefixed with "<literal>STOMP</literal>", like:
|
||
<programlisting>
|
||
hq-message-id : STOMP12345</programlisting>
|
||
If <literal>stomp-enable-message-id</literal> is not specified in the configuration, default
|
||
is <literal>false</literal>. </para>
|
||
</section>
|
||
<section>
|
||
<title>Handling of Large Messages with Stomp</title>
|
||
<para>Stomp clients may send very large bodys of frames which can exceed the size of ActiveMQ
|
||
server's internal buffer, causing unexpected errors. To prevent this situation from happening,
|
||
ActiveMQ provides a stomp configuration attribute <literal>stomp-min-large-message-size</literal>.
|
||
This attribute can be configured inside a stomp acceptor, as a parameter. For example: </para>
|
||
<programlisting>
|
||
<acceptor name="stomp-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="STOMP"/>
|
||
<param key="port" value="61613"/>
|
||
<param key="stomp-min-large-message-size" value="10240"/>
|
||
</acceptor></programlisting>
|
||
<para>The type of this attribute is integer. When this attributed is configured, ActiveMQ server
|
||
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
|
||
<literal>stomp-min-large-message</literal>, the message will be persisted as a large message.
|
||
When a large message is delievered to a stomp consumer, the HorentQ server will automatically
|
||
handle the conversion from a large message to a normal message, before sending it to the client.</para>
|
||
<para>If a large message is compressed, the server will uncompressed it before sending it to
|
||
stomp clients. The default value of <literal>stomp-min-large-message-size</literal> is the same
|
||
as the default value of <link linkend="large-messages.core.config">min-large-message-size</link>.</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="stomp.websockets">
|
||
<title>Stomp Over Web Sockets</title>
|
||
<para>ActiveMQ also support Stomp over <ulink url="http://dev.w3.org/html5/websockets/">Web Sockets</ulink>. Modern web browser which support Web Sockets can send and receive
|
||
Stomp messages from ActiveMQ.</para>
|
||
<para>To enable Stomp over Web Sockets, you must configure a <literal>NettyAcceptor</literal> with a <literal>protocol</literal>
|
||
parameter set to <literal>stomp_ws</literal>:</para>
|
||
<programlisting>
|
||
<acceptor name="stomp-ws-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="STOMP_WS"/>
|
||
<param key="port" value="61614"/>
|
||
</acceptor></programlisting>
|
||
<para>With this configuration, ActiveMQ will accept Stomp connections over Web Sockets on
|
||
the port <literal>61614</literal> with the URL path <literal>/stomp</literal>.
|
||
Web browser can then connect to <literal>ws://<server>:61614/stomp</literal> using a Web Socket to send and receive Stomp
|
||
messages.</para>
|
||
<para>A companion JavaScript library to ease client-side development is available from
|
||
<ulink url="http://github.com/jmesnil/stomp-websocket">GitHub</ulink> (please see
|
||
its <ulink url="http://jmesnil.net/stomp-websocket/doc/">documentation</ulink> for a complete description).</para>
|
||
<para>The <literal>stomp-websockets</literal> example shows how to configure ActiveMQ server to have web browsers and Java
|
||
applications exchanges messages on a JMS topic.</para>
|
||
</section>
|
||
|
||
<section id="stompconnect">
|
||
<title>StompConnect</title>
|
||
<para><ulink url="http://stomp.codehaus.org/StompConnect">StompConnect</ulink> is a server that
|
||
can act as a Stomp broker and proxy the Stomp protocol to the standard JMS API.
|
||
Consequently, using StompConnect it is possible to turn ActiveMQ into a Stomp Broker and
|
||
use any of the available stomp clients. These include clients written in C, C++, c# and
|
||
.net etc.</para>
|
||
<para>To run StompConnect first start the ActiveMQ server and make sure that it is using
|
||
JNDI.</para>
|
||
<para>Stomp requires the file <literal>jndi.properties</literal> to be available on the
|
||
classpath. This should look something like:</para>
|
||
<programlisting>
|
||
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
|
||
java.naming.provider.url=jnp://localhost:1099
|
||
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces</programlisting>
|
||
<para>Make sure this file is in the classpath along with the StompConnect jar and the
|
||
ActiveMQ jars and simply run <literal>java org.codehaus.stomp.jms.Main</literal>.</para>
|
||
</section>
|
||
|
||
</section>
|
||
<section>
|
||
<title>REST</title>
|
||
<para>Please see <xref linkend="rest"/></para>
|
||
</section>
|
||
<section>
|
||
<title>AMQP</title>
|
||
<para>ActiveMQ supports the <ulink url="https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=amqp">AMQP 1.0</ulink>
|
||
specification. To enable AMQP you must configure a Netty Acceptor to receive AMQP clients, like so:</para>
|
||
<programlisting>
|
||
<acceptor name="stomp-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="AMQP"/>
|
||
<param key="port" value="5672"/>
|
||
</acceptor>
|
||
</programlisting>
|
||
<para>ActiveMQ will then accept AMQP 1.0 clients on port 5672 which is the default AMQP port.</para>
|
||
<para>There are 2 Stomp examples available see proton-j and proton-ruby which use the qpid Java and Ruby clients
|
||
respectively</para>
|
||
<section>
|
||
<title>AMQP and security</title>
|
||
<para>The ActiveMQ Server accepts AMQP SASL Authentication and will use this to map onto the underlying session created
|
||
for the connection so you can use the normal ActiveMQ security configuration.</para>
|
||
</section>
|
||
<section>
|
||
<title>AMQP Links</title>
|
||
<para>An AMQP Link is a uni directional transport for messages between a source and a target, i.e. a client and the
|
||
ActiveMQ Broker. A link will have an endpoint of which there are 2 kinds, a Sender and A Receiver. At the Broker a
|
||
Sender will have its messages converted into a ActiveMQ Message and forwarded to its destination or target. A
|
||
Receiver will map onto a ActiveMQ Server Consumer and convert ActiveMQ messages back into AMQP messages before being delivered.</para>
|
||
</section>
|
||
<section>
|
||
<title>AMQP and destinations</title>
|
||
<para>If an AMQP Link is dynamic then a temporary queue will be created and either the remote source or remote
|
||
target address will be set to the name of the temporary queue. If the Link is not dynamic then the the address
|
||
of the remote target or source will used for the queue. If this does not exist then an exception will be sent</para>
|
||
<note><para>For the next version we will add a flag to aut create durable queue but for now you will have to add them via
|
||
the configuration</para></note>
|
||
</section>
|
||
<section>
|
||
<title>AMQP and Coordinations - Handling Transactions</title>
|
||
<para>An AMQP links target can also be a Coordinator, the Coordinator is used to handle transactions. If a
|
||
coordinator is used the the underlying HormetQ Server session will be transacted and will be either rolled back
|
||
or committed via the coordinator.</para>
|
||
<note><para>AMQP allows the use of multiple transactions per session, <literal>amqp:multi-txns-per-ssn</literal>,
|
||
however in this version ActiveMQ will only support single transactions per session</para></note>
|
||
</section>
|
||
</section>
|
||
<section>
|
||
<title>OpenWire</title>
|
||
<para>ActiveMQ now supports the <ulink url="http://activemq.apache.org/openwire.html">OpenWire</ulink>
|
||
protocol so that an ActiveMQ JMS client can talk directly to a ActiveMQ server. To enable OpenWire support
|
||
you must configure a Netty Acceptor, like so:</para>
|
||
<programlisting>
|
||
<acceptor name="openwire-acceptor">
|
||
<factory-class>org.apache.activemq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
|
||
<param key="protocols" value="OPENWIRE"/>
|
||
<param key="port" value="61616"/>
|
||
</acceptor>
|
||
</programlisting>
|
||
<para>The ActiveMQ server will then listens on port 61616 for incoming openwire commands. Please note the "protocols" is not mandatory here.
|
||
The openwire configuration conforms to ActiveMQ's "Single Port" feature. Please refer to
|
||
<link linkend="configuring-transports.single-port">Configuring Single Port</link> for details.</para>
|
||
<para>Please refer to the openwire example for more coding details.</para>
|
||
<para>Currently we support ActiveMQ clients that using standard JMS APIs. In the future we will get more supports
|
||
for some advanced, ActiveMQ specific features into ActiveMQ.</para>
|
||
</section>
|
||
</chapter>
|