http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/core-bridges.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/core-bridges.xml b/docs/user-manual/en/core-bridges.xml new file mode 100644 index 0000000..9004e7f --- /dev/null +++ b/docs/user-manual/en/core-bridges.xml @@ -0,0 +1,240 @@ +<?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 "HornetQ_User_Manual.ent"> +%BOOK_ENTITIES; +]> +<chapter id="core-bridges"> + <title>Core Bridges</title> + <para>The function of a bridge is to consume messages from a source queue, and forward them to a + target address, typically on a different HornetQ server.</para> + <para>The source and target servers do not have to be in the same cluster which makes bridging + suitable for reliably sending messages from one cluster to another, for instance across a + WAN, or internet and where the connection may be unreliable.</para> + <para>The bridge has built in resilience to failure so if the target server connection is lost, + e.g. due to network failure, the bridge will retry connecting to the target until it comes + back online. When it comes back online it will resume operation as normal.</para> + <para>In summary, bridges are a way to reliably connect two separate HornetQ servers together. + With a core bridge both source and target servers must be HornetQ servers.</para> + <para>Bridges can be configured to provide <emphasis>once and only once</emphasis> delivery + guarantees even in the event of the failure of the source or the target server. They do this + by using duplicate detection (described in <xref linkend="duplicate-detection"/>).</para> + <note> + <para>Although they have similar function, don't confuse core bridges with JMS + bridges!</para> + <para>Core bridges are for linking a HornetQ node with another HornetQ node and do not use + the JMS API. A JMS Bridge is used for linking any two JMS 1.1 compliant JMS providers. + So, a JMS Bridge could be used for bridging to or from different JMS compliant messaging + system. It's always preferable to use a core bridge if you can. Core bridges use + duplicate detection to provide <emphasis>once and only once</emphasis> guarantees. To + provide the same guarantee using a JMS bridge you would have to use XA which has a + higher overhead and is more complex to configure.</para> + </note> + <section> + <title>Configuring Bridges</title> + <para>Bridges are configured in <literal>hornetq-configuration.xml</literal>. Let's kick off + with an example (this is actually from the bridge example):</para> + <programlisting> +<bridge name="my-bridge"> + <queue-name>jms.queue.sausage-factory</queue-name> + <forwarding-address>jms.queue.mincing-machine</forwarding-address> + <filter-string="name='aardvark'"/> + <transformer-class-name> + org.hornetq.jms.example.HatColourChangeTransformer + </transformer-class-name> + <retry-interval>1000</retry-interval> + <ha>true</ha> + <retry-interval-multiplier>1.0</retry-interval-multiplier> + <initial-connect-attempts>-1</initial-connect-attempts> + <reconnect-attempts>-1</reconnect-attempts> + <failover-on-server-shutdown>false</failover-on-server-shutdown> + <use-duplicate-detection>true</use-duplicate-detection> + <confirmation-window-size>10000000</confirmation-window-size> + <user>foouser</user> + <password>foopassword</password> + <static-connectors> + <connector-ref>remote-connector</connector-ref> + </static-connectors> + <!-- alternative to static-connectors + <discovery-group-ref discovery-group-name="bridge-discovery-group"/> + --> +</bridge></programlisting> + <para>In the above example we have shown all the parameters its possible to configure for a + bridge. In practice you might use many of the defaults so it won't be necessary to + specify them all explicitly.</para> + <para>Let's take a look at all the parameters in turn:</para> + <itemizedlist> + <listitem> + <para><literal>name</literal> attribute. All bridges must have a unique name in the + server.</para> + </listitem> + <listitem> + <para><literal>queue-name</literal>. This is the unique name of the local queue that + the bridge consumes from, it's a mandatory parameter.</para> + <para>The queue must already exist by the time the bridge is instantiated at + start-up.</para> + <note> + <para>If you're using JMS then normally the JMS configuration <literal + >hornetq-jms.xml</literal> is loaded after the core configuration file + <literal>hornetq-configuration.xml</literal> is loaded. If your bridge + is consuming from a JMS queue then you'll need to make sure the JMS queue is + also deployed as a core queue in the core configuration. Take a look at the + bridge example for an example of how this is done.</para> + </note> + </listitem> + <listitem> + <para><literal>forwarding-address</literal>. This is the address on the target + server that the message will be forwarded to. If a forwarding address is not + specified, then the original address of the message will be retained.</para> + </listitem> + <listitem> + <para><literal>filter-string</literal>. An optional filter string can be supplied. + If specified then only messages which match the filter expression specified in + the filter string will be forwarded. The filter string follows the HornetQ + filter expression syntax described in <xref linkend="filter-expressions" + />.</para> + </listitem> + <listitem> + <para><literal>transformer-class-name</literal>. An optional transformer-class-name + can be specified. This is the name of a user-defined class which implements the + <literal>org.hornetq.core.server.cluster.Transformer</literal> + interface.</para> + <para>If this is specified then the transformer's <literal>transform()</literal> + method will be invoked with the message before it is forwarded. This gives you + the opportunity to transform the message's header or body before forwarding + it.</para> + </listitem> + <listitem> + <para><literal>ha</literal>. This optional parameter determines whether or not this + bridge should support high availability. True means it will connect to any available + server in a cluster and support failover. The default value is <literal + >false</literal>.</para> + </listitem> + <listitem> + <para><literal>retry-interval</literal>. This optional parameter determines the + period in milliseconds between subsequent reconnection attempts, if the + connection to the target server has failed. The default value is <literal + >2000</literal>milliseconds.</para> + </listitem> + <listitem> + <para><literal>retry-interval-multiplier</literal>. This optional parameter + determines determines a multiplier to apply to the time since the last retry to + compute the time to the next retry.</para> + <para>This allows you to implement an <emphasis>exponential backoff</emphasis> + between retry attempts.</para> + <para>Let's take an example:</para> + <para>If we set <literal>retry-interval</literal>to <literal>1000</literal> ms and + we set <literal>retry-interval-multiplier</literal> to <literal>2.0</literal>, + then, if the first reconnect attempt fails, we will wait <literal>1000</literal> + ms then <literal>2000</literal> ms then <literal>4000</literal> ms between + subsequent reconnection attempts.</para> + <para>The default value is <literal>1.0</literal> meaning each reconnect attempt is + spaced at equal intervals.</para> + </listitem> + <listitem> + <para><literal>initial-connect-attempts</literal>. This optional parameter determines the + total number of initial connect attempts the bridge will make before giving up and + shutting down. A value of <literal>-1</literal> signifies an unlimited number of + attempts. The default value is <literal>-1</literal>.</para> + </listitem> + <listitem> + <para><literal>reconnect-attempts</literal>. This optional parameter determines the + total number of reconnect attempts the bridge will make before giving up and + shutting down. A value of <literal>-1</literal> signifies an unlimited number of + attempts. The default value is <literal>-1</literal>.</para> + </listitem> + <listitem> + <para><literal>failover-on-server-shutdown</literal>. This optional parameter + determines whether the bridge will attempt to failover onto a backup server (if + specified) when the target server is cleanly shutdown rather than + crashed.</para> + <para>The bridge connector can specify both a live and a backup server, if it + specifies a backup server and this parameter is set to <literal>true</literal> + then if the target server is <emphasis>cleanly</emphasis> shutdown the bridge + connection will attempt to failover onto its backup. If the bridge connector has + no backup server configured then this parameter has no effect. </para> + <para>Sometimes you want a bridge configured with a live and a backup target server, + but you don't want to failover to the backup if the live server is simply taken + down temporarily for maintenance, this is when this parameter comes in + handy.</para> + <para>The default value for this parameter is <literal>false</literal>.</para> + </listitem> + <listitem> + <para><literal>use-duplicate-detection</literal>. This optional parameter determines + whether the bridge will automatically insert a duplicate id property into each + message that it forwards.</para> + <para>Doing so, allows the target server to perform duplicate detection on messages + it receives from the source server. If the connection fails or server crashes, + then, when the bridge resumes it will resend unacknowledged messages. This might + result in duplicate messages being sent to the target server. By enabling + duplicate detection allows these duplicates to be screened out and + ignored.</para> + <para>This allows the bridge to provide a <emphasis>once and only once</emphasis> + delivery guarantee without using heavyweight methods such as XA (see <xref + linkend="duplicate-detection"/> for more information).</para> + <para>The default value for this parameter is <literal>true</literal>.</para> + </listitem> + <listitem> + <para><literal>confirmation-window-size</literal>. This optional parameter + determines the <literal>confirmation-window-size</literal> to use for the + connection used to forward messages to the target node. This attribute is + described in section <xref linkend="client-reconnection"/></para> + + <warning><para>When using the bridge to forward messages from a queue which has a + max-size-bytes set it's important that confirmation-window-size is less than + or equal to <literal>max-size-bytes</literal> to prevent the flow of + messages from ceasing.</para> + </warning> + + </listitem> + <listitem> + <para><literal>user</literal>. This optional parameter determines the user name to + use when creating the bridge connection to the remote server. If it is not + specified the default cluster user specified by <literal>cluster-user</literal> + in <literal>hornetq-configuration.xml</literal> will be used. </para> + </listitem> + <listitem> + <para><literal>password</literal>. This optional parameter determines the password + to use when creating the bridge connection to the remote server. If it is not + specified the default cluster password specified by <literal + >cluster-password</literal> in <literal>hornetq-configuration.xml</literal> + will be used. </para> + </listitem> + <listitem> + <para><literal>static-connectors</literal> or <literal>discovery-group-ref</literal>. + Pick either of these options to connect the bridge to the target server. + </para> + <para> The <literal>static-connectors</literal> is a list of <literal>connector-ref</literal> + elements pointing to <literal>connector</literal> elements defined elsewhere. + A <emphasis>connector</emphasis> encapsulates knowledge of what transport to + use (TCP, SSL, HTTP etc) as well as the server connection parameters (host, port + etc). For more information about what connectors are and how to configure them, + please see <xref linkend="configuring-transports"/>. + </para> + <para>The <literal>discovery-group-ref</literal> element has one attribute - + <literal>discovery-group-name</literal>. This attribute points to a + <literal>discovery-group</literal> defined elsewhere. For more information about + what discovery-groups are and how to configure them, please see + <xref linkend="clusters.discovery-groups"/>. + </para> + </listitem> + </itemizedlist> + </section> +</chapter>
http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/diagrams/architecture-diagrams.odg ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/diagrams/architecture-diagrams.odg b/docs/user-manual/en/diagrams/architecture-diagrams.odg new file mode 100644 index 0000000..33d99cf Binary files /dev/null and b/docs/user-manual/en/diagrams/architecture-diagrams.odg differ http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/diagrams/ha-replicated-store.odg ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/diagrams/ha-replicated-store.odg b/docs/user-manual/en/diagrams/ha-replicated-store.odg new file mode 100644 index 0000000..495c672 Binary files /dev/null and b/docs/user-manual/en/diagrams/ha-replicated-store.odg differ http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/diagrams/ha-shared-store.odg ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/diagrams/ha-shared-store.odg b/docs/user-manual/en/diagrams/ha-shared-store.odg new file mode 100644 index 0000000..3b97692 Binary files /dev/null and b/docs/user-manual/en/diagrams/ha-shared-store.odg differ http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/diverts.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/diverts.xml b/docs/user-manual/en/diverts.xml new file mode 100644 index 0000000..3cddf09 --- /dev/null +++ b/docs/user-manual/en/diverts.xml @@ -0,0 +1,114 @@ +<?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 "HornetQ_User_Manual.ent"> +%BOOK_ENTITIES; +]> + +<chapter id="diverts"> + <title>Diverting and Splitting Message Flows</title> + <para>HornetQ allows you to configure objects called <emphasis>diverts</emphasis> with + some simple server configuration.</para> + <para>Diverts allow you to transparently divert messages routed to one address to some other + address, without making any changes to any client application logic.</para> + <para>Diverts can be <emphasis>exclusive</emphasis>, meaning that the message is diverted + to the new address, and does not go to the old address at all, or they can be + <emphasis>non-exclusive</emphasis> which means the message continues to go the old + address, and a <emphasis>copy</emphasis> of it is also sent to the new address. + Non-exclusive diverts can therefore be used for <emphasis>splitting</emphasis> message + flows, e.g. there may be a requirement to monitor every order sent to an order queue.</para> + <para>Diverts can also be configured to have an optional message filter. If specified then only + messages that match the filter will be diverted.</para> + <para>Diverts can also be configured to apply a <literal>Transformer</literal>. If specified, + all diverted messages will have the opportunity of being transformed by the <literal + >Transformer</literal>.</para> + <para>A divert will only divert a message to an address on the <emphasis>same server</emphasis>, + however, if you want to divert to an address on a different server, a common pattern would + be to divert to a local store-and-forward queue, then set up a bridge which consumes from + that queue and forwards to an address on a different server.</para> + <para>Diverts are therefore a very sophisticated concept, which when combined with bridges can + be used to create interesting and complex routings. The set of diverts on a server can be + thought of as a type of routing table for messages. Combining diverts with bridges allows + you to create a distributed network of reliable routing connections between multiple + geographically distributed servers, creating your global messaging mesh.</para> + <para>Diverts are defined as xml in the <literal>hornetq-configuration.xml</literal> file. There can + be zero or more diverts in the file.</para> + <para>Please see <xref linkend="divert-example" /> for a full working + example showing you how to configure and use diverts.</para> + <para>Let's take a look at some divert examples:</para> + <section> + <title>Exclusive Divert</title> + <para>Let's take a look at an exclusive divert. An exclusive divert diverts all matching + messages that are routed to the old address to the new address. Matching messages do not + get routed to the old address.</para> + <para>Here's some example xml configuration for an exclusive divert, it's taken from the + divert example:</para> + <programlisting> +<divert name="prices-divert"> + <address>jms.topic.priceUpdates</address> + <forwarding-address>jms.queue.priceForwarding</forwarding-address> + <filter string="office='New York'"/> + <transformer-class-name> + org.hornetq.jms.example.AddForwardingTimeTransformer + </transformer-class-name> + <exclusive>true</exclusive> +</divert></programlisting> + <para>We define a divert called '<literal>prices-divert</literal>' that will divert any + messages sent to the address '<literal>jms.topic.priceUpdates</literal>' (this + corresponds to any messages sent to a JMS Topic called '<literal + >priceUpdates</literal>') to another local address '<literal + >jms.queue.priceForwarding</literal>' (this corresponds to a local JMS queue called + '<literal>priceForwarding</literal>'</para> + <para>We also specify a message filter string so only messages with the message property + <literal>office</literal> with value <literal>New York</literal> will get diverted, + all other messages will continue to be routed to the normal address. The filter string + is optional, if not specified then all messages will be considered matched.</para> + <para>In this example a transformer class is specified. Again this is optional, and if + specified the transformer will be executed for each matching message. This allows you to + change the messages body or properties before it is diverted. In this example the + transformer simply adds a header that records the time the divert happened.</para> + <para>This example is actually diverting messages to a local store and forward queue, which + is configured with a bridge which forwards the message to an address on another HornetQ + server. Please see the example for more details.</para> + </section> + <section> + <title>Non-exclusive Divert</title> + <para>Now we'll take a look at a non-exclusive divert. Non exclusive diverts are the same as + exclusive diverts, but they only forward a <emphasis>copy</emphasis> of the message to + the new address. The original message continues to the old address</para> + <para>You can therefore think of non-exclusive diverts as <emphasis>splitting</emphasis> a + message flow.</para> + <para>Non exclusive diverts can be configured in the same way as exclusive diverts with an + optional filter and transformer, here's an example non-exclusive divert, again from the + divert example:</para> + <programlisting> +<divert name="order-divert"> + <address>jms.queue.orders</address> + <forwarding-address>jms.topic.spyTopic</forwarding-address> + <exclusive>false</exclusive> +</divert></programlisting> + <para>The above divert example takes a copy of every message sent to the address '<literal + >jms.queue.orders</literal>' (Which corresponds to a JMS Queue called '<literal + >orders</literal>') and sends it to a local address called '<literal + >jms.topic.SpyTopic</literal>' (which corresponds to a JMS Topic called '<literal + >SpyTopic</literal>').</para> + </section> +</chapter> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/duplicate-detection.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/duplicate-detection.xml b/docs/user-manual/en/duplicate-detection.xml new file mode 100644 index 0000000..c2577ff --- /dev/null +++ b/docs/user-manual/en/duplicate-detection.xml @@ -0,0 +1,149 @@ +<?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 "HornetQ_User_Manual.ent"> +%BOOK_ENTITIES; +]> + +<chapter id="duplicate-detection"> + <title>Duplicate Message Detection</title> + <para>HornetQ includes powerful automatic duplicate message detection, filtering out + duplicate messages without you having to code your own fiddly duplicate detection logic at + the application level. This chapter will explain what duplicate detection is, how HornetQ + uses it and how and where to configure it.</para> + <para>When sending messages from a client to a server, or indeed from a server to another + server, if the target server or connection fails sometime after sending the message, but + before the sender receives a response that the send (or commit) was processed successfully + then the sender cannot know for sure if the message was sent successfully to the + address.</para> + <para>If the target server or connection failed after the send was received and processed but + before the response was sent back then the message will have been sent to the address + successfully, but if the target server or connection failed before the send was received and + finished processing then it will not have been sent to the address successfully. From the + senders point of view it's not possible to distinguish these two cases.</para> + <para>When the server recovers this leaves the client in a difficult situation. It knows the + target server failed, but it does not know if the last message reached its destination ok. + If it decides to resend the last message, then that could result in a duplicate message + being sent to the address. If each message was an order or a trade then this could result in + the order being fulfilled twice or the trade being double booked. This is clearly not a + desirable situation.</para> + <para>Sending the message(s) in a transaction does not help out either. If the server or + connection fails while the transaction commit is being processed it is also indeterminate + whether the transaction was successfully committed or not!</para> + <para>To solve these issues HornetQ provides automatic duplicate messages detection for + messages sent to addresses.</para> + <section> + <title>Using Duplicate Detection for Message Sending</title> + <para>Enabling duplicate message detection for sent messages is simple: you just need to set + a special property on the message to a unique value. You can create the value however + you like, as long as it is unique. When the target server receives the message it will + check if that property is set, if it is, then it will check in its in memory cache if it + has already received a message with that value of the header. If it has received a + message with the same value before then it will ignore the message.</para> + <note> + <para>Using duplicate detection to move messages between nodes can give you the same + <emphasis>once and only once</emphasis> delivery guarantees as if you were using + an XA transaction to consume messages from source and send them to the target, but + with less overhead and much easier configuration than using XA.</para> + </note> + <para>If you're sending messages in a transaction then you don't have to set the property + for <emphasis>every</emphasis> message you send in that transaction, you only need to + set it once in the transaction. If the server detects a duplicate message for any + message in the transaction, then it will ignore the entire transaction.</para> + <para>The name of the property that you set is given by the value of <literal + >org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID</literal>, which + is <literal>_HQ_DUPL_ID</literal></para> + <para>The value of the property can be of type <literal>byte[]</literal> or <literal + >SimpleString</literal> if you're using the core API. If you're using JMS it must be + a <literal>String</literal>, and its value should be unique. An easy way of generating + a unique id is by generating a UUID.</para> + <para>Here's an example of setting the property using the core API:</para> + <programlisting> +... + +ClientMessage message = session.createMessage(true); + +SimpleString myUniqueID = "This is my unique id"; // Could use a UUID for this + +message.setStringProperty(HDR_DUPLICATE_DETECTION_ID, myUniqueID); + +...</programlisting> + <para>And here's an example using the JMS API:</para> + <programlisting> +... + +Message jmsMessage = session.createMessage(); + +String myUniqueID = "This is my unique id"; // Could use a UUID for this + +message.setStringProperty(HDR_DUPLICATE_DETECTION_ID.toString(), myUniqueID); + +...</programlisting> + </section> + <section id="duplicate.id.cache"> + <title>Configuring the Duplicate ID Cache</title> + <para>The server maintains caches of received values of the <literal + >org.hornetq.core.message.impl.HDR_DUPLICATE_DETECTION_ID</literal> property + sent to each address. Each address has its own distinct cache.</para> + <para>The cache is a circular fixed size cache. If the cache has a maximum size of <literal + >n</literal> elements, then the <literal>n + 1</literal>th id stored will overwrite + the <literal>0</literal>th element in the cache.</para> + <para>The maximum size of the cache is configured by the parameter <literal + >id-cache-size</literal> in <literal>hornetq-configuration.xml</literal>, the default + value is <literal>2000</literal> elements.</para> + <para>The caches can also be configured to persist to disk or not. This is configured by the + parameter <literal>persist-id-cache</literal>, also in <literal + >hornetq-configuration.xml</literal>. If this is set to <literal>true</literal> then + each id will be persisted to permanent storage as they are received. The default value + for this parameter is <literal>true</literal>.</para> + <note> + <para>When choosing a size of the duplicate id cache be sure to set it to a larger + enough size so if you resend messages all the previously sent ones are in the cache + not having been overwritten.</para> + </note> + </section> + <section> + <title>Duplicate Detection and Bridges</title> + <para>Core bridges can be configured to automatically add a unique duplicate id value (if there + isn't already one in the message) before forwarding the message to it's target. This + ensures that if the target server crashes or the connection is interrupted and the + bridge resends the message, then if it has already been received by the target server, + it will be ignored.</para> + <para>To configure a core bridge to add the duplicate id header, simply set the <parameter + >use-duplicate-detection</parameter> to <literal>true</literal> when configuring a + bridge in <literal>hornetq-configuration.xml</literal>.</para> + <para>The default value for this parameter is <literal>true</literal>.</para> + <para>For more information on core bridges and how to configure them, please see + <xref linkend="core-bridges" />.</para> + </section> + <section> + <title>Duplicate Detection and Cluster Connections</title> + <para>Cluster connections internally use core bridges to move messages reliable between + nodes of the cluster. Consequently they can also be configured to insert the duplicate + id header for each message they move using their internal bridges.</para> + <para>To configure a cluster connection to add the duplicate id header, simply set the + <parameter>use-duplicate-detection</parameter> to <literal>true</literal> when + configuring a cluster connection in <literal>hornetq-configuration.xml</literal>.</para> + <para>The default value for this parameter is <literal>true</literal>.</para> + <para>For more information on cluster connections and how to configure them, please see <xref + linkend="clusters"/>.</para> + </section> +</chapter> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/docs/user-manual/en/embedding-hornetq.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/embedding-hornetq.xml b/docs/user-manual/en/embedding-hornetq.xml new file mode 100644 index 0000000..e2bea3a --- /dev/null +++ b/docs/user-manual/en/embedding-hornetq.xml @@ -0,0 +1,271 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN" +"../../../lib/docbook-support/support/docbook-dtd/docbookx.dtd"> --> +<!-- ============================================================================= --> +<!-- 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 "HornetQ_User_Manual.ent"> +%BOOK_ENTITIES; +]> +<chapter id="embedding-hornetq"> + <title>Embedding HornetQ</title> + + <para>HornetQ is designed as set of simple Plain Old Java Objects (POJOs). + This means HornetQ can be instantiated and run in any dependency injection + framework such as JBoss Microcontainer, Spring or Google Guice. It also + means that if you have an application that could use messaging functionality + internally, then it can <emphasis>directly instantiate</emphasis> HornetQ + clients and servers in its own application code to perform that + functionality. We call this <emphasis>embedding</emphasis> HornetQ.</para> + + <para>Examples of applications that might want to do this include any + application that needs very high performance, transactional, persistent + messaging but doesn't want the hassle of writing it all from scratch.</para> + + <para>Embedding HornetQ can be done in very few easy steps. Instantiate the + configuration object, instantiate the server, start it, and you have a + HornetQ running in your virtual machine. It's as simple and easy as + that.</para> + + <section> + <title>Simple Config File Embedding</title> + + <para>The simplest way to embed HornetQ is to use the embedded wrapper + classes and configure HornetQ through its configuration files. There are + two different helper classes for this depending on whether your using the + HornetQ Core API or JMS.</para> + + <section> + <title>Core API Only</title> + <para>For instantiating a core HornetQ Server only, the steps are pretty + simple. The example requires that you have defined a configuration file + <literal>hornetq-configuration.xml</literal> in your + classpath:</para> + <programlisting> +import org.hornetq.core.server.embedded.EmbeddedHornetQ; + +... + +EmbeddedHornetQ embedded = new EmbeddedHornetQ(); +embedded.start(); + +ClientSessionFactory nettyFactory = HornetQClient.createClientSessionFactory( + new TransportConfiguration( + InVMConnectorFactory.class.getName())); + +ClientSession session = factory.createSession(); + +session.createQueue("example", "example", true); + +ClientProducer producer = session.createProducer("example"); + +ClientMessage message = session.createMessage(true); + +message.getBody().writeString("Hello"); + +producer.send(message); + +session.start(); + +ClientConsumer consumer = session.createConsumer("example"); + +ClientMessage msgReceived = consumer.receive(); + +System.out.println("message = " + msgReceived.getBody().readString()); + +session.close();</programlisting> + +<para>The <literal>EmbeddedHornetQ</literal> class has a + few additional setter methods that allow you to specify a different + config file name as well as other properties. See the javadocs for this + class for more details.</para> + </section> + + <section id="simple.embedded.jms"> + <title>JMS API</title> + + <para>JMS embedding is simple as well. This example requires that you + have defined the config files + <literal>hornetq-configuration.xml</literal>, + <literal>hornetq-jms.xml</literal>, and a + <literal>hornetq-users.xml</literal> if you have security enabled. Let's + also assume that a queue and connection factory has been defined in the + <literal>hornetq-jms.xml</literal> config file.</para> + + <programlisting> +import org.hornetq.jms.server.embedded.EmbeddedJMS; + +... + +EmbeddedJMS jms = new EmbeddedJMS(); +jms.start(); + +// This assumes we have configured hornetq-jms.xml with the appropriate config information +ConnectionFactory connectionFactory = jms.lookup("ConnectionFactory"); +Destination destination = jms.lookup("/example/queue"); + +... regular JMS code ...</programlisting> + <para>By default, the <literal>EmbeddedJMS</literal> + class will store component entries defined within your + <literal>hornetq-jms.xml</literal> file in an internal concurrent hash + map. The <literal>EmbeddedJMS.lookup()</literal> method returns + components stored in this map. If you want to use JNDI, call the + <literal>EmbeddedJMS.setContext()</literal> method with the root JNDI + context you want your components bound into. See the javadocs for this + class for more details on other config options.</para> + </section> + </section> + + <section> + <title>POJO instantiation - Embedding Programmatically</title> + + <para>You can follow this step-by-step guide to programmatically embed the + core, non-JMS HornetQ Server instance:</para> + + <para>Create the configuration object - this contains configuration + information for a HornetQ instance. The setter methods of this class allow + you to programmatically set configuration options as describe in the <xref + linkend="server.configuration" /> section.</para> + + <para>The acceptors are configured through + <literal>ConfigurationImpl</literal>. Just add the + <literal>NettyAcceptorFactory</literal> on the transports the same way you + would through the main configuration file.</para> + + <programlisting> +import org.hornetq.core.config.Configuration; +import org.hornetq.core.config.impl.ConfigurationImpl; + +... + +Configuration config = new ConfigurationImpl(); +HashSet<TransportConfiguration> transports = new HashSet<TransportConfiguration>(); + +transports.add(new TransportConfiguration(NettyAcceptorFactory.class.getName())); +transports.add(new TransportConfiguration(InVMAcceptorFactory.class.getName())); + +config.setAcceptorConfigurations(transports);</programlisting> + + <para>You need to instantiate an instance of + <literal>org.hornetq.api.core.server.embedded.EmbeddedHornetQ</literal> + and add the configuration object to it.</para> + + <programlisting> +import org.hornetq.api.core.server.HornetQ; +import org.hornetq.core.server.embedded.EmbeddedHornetQ; + +... + +EmbeddedHornetQ server = new EmbeddedHornetQ(); +server.setConfiguration(config); + +server.start();</programlisting> + + <para>You also have the option of instantiating + <literal>HornetQServerImpl</literal> directly:</para> + + <programlisting> +HornetQServer server = new HornetQServerImpl(config); +server.start();</programlisting> + + <para>For JMS POJO instantiation, you work with the EmbeddedJMS class + instead as described earlier. First you define the configuration + programmatically for your ConnectionFactory and Destination objects, then + set the JmsConfiguration property of the EmbeddedJMS class. Here is an + example of this:</para> + + <programlisting> +// Step 1. Create HornetQ core configuration, and set the properties accordingly +Configuration configuration = new ConfigurationImpl(); +configuration.setPersistenceEnabled(false); +configuration.setSecurityEnabled(false); +configuration.getAcceptorConfigurations().add(new TransportConfiguration(NettyAcceptorFactory.class.getName())); + +// Step 2. Create the JMS configuration +JMSConfiguration jmsConfig = new JMSConfigurationImpl(); + +// Step 3. Configure the JMS ConnectionFactory +TransportConfiguration connectorConfig = new TransportConfiguration(NettyConnectorFactory.class.getName()); +ConnectionFactoryConfiguration cfConfig = new ConnectionFactoryConfigurationImpl("cf", connectorConfig, "/cf"); +jmsConfig.getConnectionFactoryConfigurations().add(cfConfig); + +// Step 4. Configure the JMS Queue +JMSQueueConfiguration queueConfig = new JMSQueueConfigurationImpl("queue1", null, false, "/queue/queue1"); +jmsConfig.getQueueConfigurations().add(queueConfig); + +// Step 5. Start the JMS Server using the HornetQ core server and the JMS configuration +EmbeddedJMS jmsServer = new EmbeddedJMS(); +jmsServer.setConfiguration(configuration); +jmsServer.setJmsConfiguration(jmsConfig); +jmsServer.start();</programlisting> + + <para>Please see <xref linkend="examples.embedded.jms" /> for an example which + shows how to setup and run HornetQ embedded with JMS.</para> + </section> + + <section> + <title>Dependency Frameworks</title> + + <para>You may also choose to use a dependency injection framework such as + <trademark>JBoss Micro Container</trademark> or <trademark>Spring + Framework</trademark>. See <xref linkend="spring.integration" /> for more + details on Spring and HornetQ, but here's how you would do things with the + JBoss Micro Container.</para> + + <para>HornetQ standalone uses JBoss Micro Container as the injection + framework. <literal>HornetQBootstrapServer</literal> and + <literal>hornetq-beans.xml</literal> which are part of the HornetQ + distribution provide a very complete implementation of what's needed to + bootstrap the server using JBoss Micro Container.</para> + + <para>When using JBoss Micro Container, you need to provide an XML file + declaring the <literal>HornetQServer</literal> and + <literal>Configuration</literal> object, you can also inject a security + manager and a MBean server if you want, but those are optional.</para> + + <para>A very basic XML Bean declaration for the JBoss Micro Container + would be:</para> + + <programlisting> +<?xml version="1.0" encoding="UTF-8"?> +<deployment xmlns="urn:jboss:bean-deployer:2.0"> + <!-- The core configuration --> + <bean name="Configuration" + class="org.hornetq.core.config.impl.FileConfiguration"> + </bean> + + <!-- The core server --> + <bean name="HornetQServer" + class="org.hornetq.core.server.impl.HornetQServerImpl"> + <constructor> + <parameter> + <inject bean="Configuration"/> + </parameter> + </constructor> + </bean> +</deployment></programlisting> + + <para><literal>HornetQBootstrapServer</literal> provides an easy + encapsulation of JBoss Micro Container.</para> + + <programlisting> +HornetQBootstrapServer bootStrap = new HornetQBootstrapServer(new String[] {"hornetq-beans.xml"}); +bootStrap.run();</programlisting> + </section> +</chapter>