<!--
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.
-->
<html>
<head>
<title>ActiveMQ Artemis Large Message Example</title>
<link rel="stylesheet" type="text/css" href="../common/common.css" />
<link rel="stylesheet" type="text/css" href="../common/prettify.css" />
<script type="text/javascript" src="../common/prettify.js"></script>
</head>
<body onload="prettyPrint()">
<h1>Large Message Example</h1>
<p>This example shows you how to send and receive very large messages with ActiveMQ Artemis.</p>
<p>ActiveMQ Artemis supports the sending and receiving of huge messages, much larger than can fit in available RAM
on the client or server. Effectively the only limit to message size is the amount of disk space you have on the server.</p>
<p>Large messages are persisted on the server so they can survive a server restart. In other words ActiveMQ Artemis doesn't just
do a simple socket stream from the sender to the consumer.</p>
<p>In order to do this ActiveMQ Artemis provides an extension to JMS where you can use an InputStream or OutputStream as the source and destination for your messages. You can send messages as large as it would fit in your disk.</p>
<p>You may also choose to read LargeMessages using the regular ByteStream or ByteMessage methods, but using the InputStream and OutputStream will provide you a much better performance</p>
<h2>Example step-by-step</h2>
<p><i>To run the example, simply type <code>mvn verify -Pexample</code> from this directory</i></p>
<p>In this example we limit both the server and the client to be running in a maximum of 50MB of RAM,
and we send a message with a body of size 256MB.</p>
<p>ActiveMQ Artemis can support much large message sizes but we
choose these sizes and limit RAM so the example runs more quickly.</p>
<p>We create a file on disk representing the message body, create
a FileInputStream on that file and set that InputStream as the body of the message before sending.</p>
<p>The message is sent, then we stop the server, and restart it. This demonstrates the large message will survive a restart of the server.</p>
<p>Once the server is restarted we receive the message and stream it's body to another file on disk.</p>
<ol>
<li>Create an initial context to perform the JNDI lookup.</li>
<pre class="prettyprint">
<code>initialContext = getContext(0);</code>
</pre>
<li>Perfom a lookup on the queue.</li>
<pre class="prettyprint">
<code>Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");</code>
</pre>
<li>Perform a lookup on the Connection Factory. This ConnectionFactory has a special attribute set on it. activemq-jms.xml)
Messages with more than 10K are considered large.</li>
<pre class="prettyprint">
<code>ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");</code>
</pre>
<li>Create the JMS objects for sending the message.</li>
<pre class="prettyprint">
<code>
connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(queue);
</code>
</pre>
<li>Create a huge file - this will form the body of the message we will send.</li>
<pre class="prettyprint">
<code>
File fileInput = new File("huge_message_to_send.dat");
fileInput.createNewFile();
createFile(fileInput, FILE_SIZE);
</code>
</pre>
<li>Create a BytesMessage</li>
<pre class="prettyprint">
<code>BytesMessage message = session.createBytesMessage();</code>
</pre>
<li>We set the InputStream on the message. When sending the message will read the InputStream
until it gets EOF. In this case we point the InputStream at a file on disk, and it will suck up the entire
file, however we could use any InputStream not just a FileInputStream.</li>
<pre class="prettyprint"><code>
FileInputStream fileInputStream = new FileInputStream(fileInput);
BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream);
message.setObjectProperty("JMS_AMQ_InputStream", bufferedInput);
</code></pre>
<li>Send the Message.</li>
<pre class="prettyprint"><code>
producer.send(message);
</code></pre>
<li>We send message to the queue. After the send completion the message file will be located at ./build/data/largeMessages</li>
<pre class="prettyprint">
<code>messageProducer.send(message);</code>
</pre>
<li>
To demonstrate that that we're not simply streaming the message from sending to consumer, we stop
the server and restart it before consuming the message. This demonstrates that the large message gets persisted, like a
normal persistent message, on the server. If you look at ./build/data/largeMessages you will see the largeMessage
stored on disk the server.
</li>
<pre class="prettyprint">
<code>
connection.close();
initialContext.close();
stopServer(0);
// Give the server a little time to shutdown properly
Thread.sleep(5000);
startServer(0);
</code>
</pre>
<li>Now the server is restarted we can recreate the JMS Objects, and start the new connection.</li>
<pre class="prettyprint">
<code>
initialContext = getContext(0);
queue = (Queue)initialContext.lookup("/queue/exampleQueue");
cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
connection = cf.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer messageConsumer = session.createConsumer(queue);
connection.start();
</code>
</pre>
<li>Receive the message. When we receive the large message we initially just receive the message with
an empty body.</li>
<pre class="prettyprint"><code>BytesMessage messageReceived = (BytesMessage)messageConsumer.receive(120000);
</code></pre>
<li>We set an OutputStream on the message. This causes the message body to be written to the
OutputStream until there are no more bytes to be written.
You don't have to use a FileOutputStream, you can use any OutputStream.
You may choose to use the regular BytesMessage or
StreamMessage interface but this method is much faster for large messages.</li>
<pre class="prettyprint"><code>
File outputFile = new File("huge_message_received.dat");
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream);
</code></pre>
<li>This will save the stream and wait until the entire message is written before continuing.</li>
<pre class="prettyprint"><code>
messageReceived.setObjectProperty("JMS_AMQ_SaveStream", bufferedOutput);
</code></pre>
<li>Be sure to close our resources!</li>
<pre class="prettyprint">
<code>
finally
{
if (initialContext != null)
{
initialContext.close();
}
if (connection != null)
{
connection.close();
}
}</code>
</pre>
</ol>
</body>
</html>