diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..fd63cefc44
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,754 @@
+#idea files
+hornetq-pom.ipr
+hornetq-pom.iws
+.idea
+*.iml
+*/*.iml
+*/*/*.iml
+*/*/*/*.iml
+dependency-reduced-pom.xml
+*/dependency-reduced-pom.xml
+*/*/dependency-reduced-pom.xml
+*/*/*dependency-reduced-pom.xml
+.factorypath
+
+# compilation from native
+*/*/bin
+*~
+
+target
+tests/integration-tests/data/
+tests/joram-tests/data/
+org.eclipse.jdt.core.prefs
+org.eclipse.jdt.ui.prefs
+org.eclipse.m2e.core.prefs
+*/.settings/org.eclipse.*
+*/*/.settings/org.eclipse.*
+examples/*/*/.settings/org.eclipse.*
+examples/*/*/.project
+examples/*/.project
+!etc/org.eclipse.jdt.ui.prefs
+!etc/org.eclipse.jdt.core.prefs
+org.maven.ide.eclipse.prefs
+.classpath
+tests/*-tests/hs_err_pid*.log
+tests/**/server.lock
+hornetq-core/*.log
+.checkstyle
+
+# /
+/build
+/eclipse-output
+/thirdparty
+/logs
+/ObjectStore
+/tmp
+/data
+/junit*.properties
+/target
+/.metadata
+
+integration/hornetq-*-integration/.project
+
+# /distribution/
+/distribution/target
+/distribution/.project
+/distribution/jboss-mc/.project
+
+# /distribution/hornetq/
+/distribution/hornetq/.project
+
+# /distribution/jnp-client/
+/distribution/jnp-client/target
+/distribution/jnp-client/bin
+/distribution/jnp-client/.project
+
+# /docs/
+/docs/.project
+
+# /docs/eap-manual/
+/docs/eap-manual/build
+
+# /docs/quickstart-guide/
+/docs/quickstart-guide/build
+/docs/quickstart-guide/target
+
+# /docs/user-manual/
+/docs/user-manual/build
+/docs/user-manual/target
+/docs/user-manual/bin
+/docs/user-manual/.project
+
+# /examples/
+/examples/bin
+/examples/.project
+
+# /examples/common/
+/examples/common/build
+
+# /examples/core/embedded/
+/examples/core/embedded/logs
+/examples/core/embedded/build
+
+# /examples/core/embedded-remote/
+/examples/core/embedded-remote/build
+
+# /examples/core/microcontainer/
+/examples/core/microcontainer/build
+
+# /examples/core/perf/
+/examples/core/perf/build
+/examples/core/perf/data
+/examples/core/perf/logs
+
+# /examples/javaee/ejb-jms-transaction/
+/examples/javaee/ejb-jms-transaction/build
+
+# /examples/javaee/hajndi/
+/examples/javaee/hajndi/build
+
+# /examples/javaee/jca-config/
+/examples/javaee/jca-config/build
+
+# /examples/javaee/jms-bridge/
+/examples/javaee/jms-bridge/build
+
+# /examples/javaee/mdb-cmt-tx-local/
+/examples/javaee/mdb-cmt-tx-local/build
+
+# /examples/javaee/mdb-cmt-tx-required/
+/examples/javaee/mdb-cmt-tx-required/build
+
+# /examples/javaee/servlet-ssl/
+/examples/javaee/servlet-ssl/build
+
+# /examples/javaee/servlet-transport/
+/examples/javaee/servlet-transport/build
+
+# /examples/javaee/xarecovery/
+/examples/javaee/xarecovery/build
+
+# /examples/
+/examples/build
+
+# /examples/applet/
+/examples/applet/build
+
+# /examples/applet/server0/
+/examples/applet/server0/data
+
+# /examples/application-layer-failover/
+/examples/application-layer-failover/build
+/examples/application-layer-failover/logs
+
+# /examples/application-layer-failover/server0/
+/examples/application-layer-failover/server0/data
+/examples/application-layer-failover/server0/logs
+
+# /examples/application-layer-failover/server1/
+/examples/application-layer-failover/server1/data
+/examples/application-layer-failover/server1/logs
+/examples/application-layer-failover/server1/KILL_ME
+
+# /examples/bridge/
+/examples/bridge/build
+/examples/bridge/logs
+
+# /examples/bridge/server0/
+/examples/bridge/server0/data
+/examples/bridge/server0/logs
+
+# /examples/bridge/server1/
+/examples/bridge/server1/data
+/examples/bridge/server1/logs
+
+# /examples/browser/
+/examples/browser/build
+/examples/browser/logs
+
+# /examples/browser/server0/
+/examples/browser/server0/data
+/examples/browser/server0/logs
+
+# /examples/client-kickoff/
+/examples/client-kickoff/build
+/examples/client-kickoff/logs
+
+# /examples/client-kickoff/server0/
+/examples/client-kickoff/server0/data
+/examples/client-kickoff/server0/logs
+
+# /examples/client-side-load-balancing/
+/examples/client-side-load-balancing/build
+/examples/client-side-load-balancing/logs
+
+# /examples/client-side-load-balancing/server0/
+/examples/client-side-load-balancing/server0/data
+/examples/client-side-load-balancing/server0/logs
+
+# /examples/client-side-load-balancing/server1/
+/examples/client-side-load-balancing/server1/data
+/examples/client-side-load-balancing/server1/logs
+
+# /examples/client-side-load-balancing/server2/
+/examples/client-side-load-balancing/server2/data
+/examples/client-side-load-balancing/server2/logs
+
+# /examples/clustered-durable-subscription/
+/examples/clustered-durable-subscription/build
+/examples/clustered-durable-subscription/logs
+
+# /examples/clustered-durable-subscription/server0/
+/examples/clustered-durable-subscription/server0/data
+/examples/clustered-durable-subscription/server0/logs
+
+# /examples/clustered-durable-subscription/server1/
+/examples/clustered-durable-subscription/server1/data
+/examples/clustered-durable-subscription/server1/logs
+
+# /examples/clustered-queue/
+/examples/clustered-queue/build
+/examples/clustered-queue/logs
+
+# /examples/clustered-jgroups/
+/examples/clustered-jgroups/server0
+/examples/clustered-jgroups/server1
+
+# /examples/clustered-queue/server0/
+/examples/clustered-queue/server0/data
+/examples/clustered-queue/server0/logs
+
+# /examples/clustered-queue/server1/
+/examples/clustered-queue/server1/data
+/examples/clustered-queue/server1/logs
+
+# /examples/clustered-topic/
+/examples/clustered-topic/build
+/examples/clustered-topic/logs
+
+# /examples/clustered-topic/server0/
+/examples/clustered-topic/server0/data
+/examples/clustered-topic/server0/logs
+
+# /examples/clustered-topic/server1/
+/examples/clustered-topic/server1/data
+/examples/clustered-topic/server1/logs
+
+# /examples/consumer-rate-limit/
+/examples/consumer-rate-limit/build
+/examples/consumer-rate-limit/logs
+
+# /examples/consumer-rate-limit/server0/
+/examples/consumer-rate-limit/server0/data
+/examples/consumer-rate-limit/server0/logs
+
+# /examples/dead-letter/
+/examples/dead-letter/build
+/examples/dead-letter/logs
+
+# /examples/dead-letter/server0/
+/examples/dead-letter/server0/data
+/examples/dead-letter/server0/logs
+
+# /examples/delayed-redelivery/
+/examples/delayed-redelivery/build
+/examples/delayed-redelivery/logs
+
+# /examples/delayed-redelivery/server0/
+/examples/delayed-redelivery/server0/data
+/examples/delayed-redelivery/server0/logs
+
+# /examples/divert/
+/examples/divert/build
+/examples/divert/logs
+
+# /examples/divert/server0/
+/examples/divert/server0/data
+/examples/divert/server0/logs
+
+# /examples/divert/server1/
+/examples/divert/server1/data
+/examples/divert/server1/logs
+
+# /examples/durable-subscription/
+/examples/durable-subscription/build
+/examples/durable-subscription/logs
+
+# /examples/durable-subscription/server0/
+/examples/durable-subscription/server0/data
+/examples/durable-subscription/server0/logs
+
+# /examples/embedded/
+/examples/embedded/logs
+/examples/embedded/build
+
+# /examples/expiry/
+/examples/expiry/build
+/examples/expiry/logs
+
+# /examples/expiry/server0/
+/examples/expiry/server0/data
+/examples/expiry/server0/logs
+
+# /examples/http-transport/
+/examples/http-transport/build
+/examples/http-transport/logs
+
+# /examples/http-transport/server0/
+/examples/http-transport/server0/data
+/examples/http-transport/server0/logs
+
+# /examples/instantiate-connection-factory/
+/examples/instantiate-connection-factory/build
+/examples/instantiate-connection-factory/logs
+
+# /examples/instantiate-connection-factory/server0/
+/examples/instantiate-connection-factory/server0/data
+/examples/instantiate-connection-factory/server0/logs
+
+# /examples/interceptor/
+/examples/interceptor/build
+/examples/interceptor/logs
+
+# /examples/interceptor/server0/
+/examples/interceptor/server0/data
+/examples/interceptor/server0/logs
+
+# /examples/jaas/
+/examples/jaas/build
+/examples/jaas/logs
+
+# /examples/jaas/server0/
+/examples/jaas/server0/data
+/examples/jaas/server0/logs
+
+# /examples/jms-bridge/
+/examples/jms-bridge/build
+/examples/jms-bridge/data
+
+# /examples/jmx/
+/examples/jmx/build
+/examples/jmx/logs
+
+# /examples/jmx/server0/
+/examples/jmx/server0/data
+/examples/jmx/server0/logs
+
+# /examples/large-message/
+/examples/large-message/build
+/examples/large-message/logs
+/examples/large-message/huge_message_received.dat
+/examples/large-message/huge_message_to_send.dat
+
+# /examples/large-message/server0/
+/examples/large-message/server0/logs
+/examples/large-message/server0/data
+
+# /examples/last-value-queue/
+/examples/last-value-queue/build
+/examples/last-value-queue/logs
+
+# /examples/last-value-queue/server0/
+/examples/last-value-queue/server0/data
+/examples/last-value-queue/server0/logs
+
+# /examples/management/
+/examples/management/build
+/examples/management/logs
+
+# /examples/management/server0/
+/examples/management/server0/data
+/examples/management/server0/logs
+
+# /examples/management-notifications/
+/examples/management-notifications/build
+/examples/management-notifications/logs
+
+# /examples/management-notifications/server0/
+/examples/management-notifications/server0/logs
+/examples/management-notifications/server0/data
+
+# /examples/message-counters/
+/examples/message-counters/build
+/examples/message-counters/logs
+
+# /examples/message-counters/server0/
+/examples/message-counters/server0/data
+/examples/message-counters/server0/logs
+
+# /examples/message-group/
+/examples/message-group/build
+/examples/message-group/logs
+
+# /examples/message-group/server0/
+/examples/message-group/server0/data
+/examples/message-group/server0/logs
+
+# /examples/message-priority/
+/examples/message-priority/build
+/examples/message-priority/logs
+
+# /examples/message-priority/server0/
+/examples/message-priority/server0/data
+/examples/message-priority/server0/logs
+
+# /examples/no-consumer-buffering/
+/examples/no-consumer-buffering/build
+/examples/no-consumer-buffering/logs
+
+# /examples/no-consumer-buffering/server0/
+/examples/no-consumer-buffering/server0/data
+/examples/no-consumer-buffering/server0/logs
+
+# /examples/non-transaction-failover/
+/examples/non-transaction-failover/build
+
+# /examples/non-transaction-failover/server0/
+/examples/non-transaction-failover/server0/data
+
+# /examples/non-transaction-failover/server1/
+/examples/non-transaction-failover/server1/data
+
+# /examples/paging/
+/examples/paging/build
+/examples/paging/logs
+
+# /examples/paging/server0/
+/examples/paging/server0/data
+/examples/paging/server0/logs
+
+# /examples/perf/
+/examples/perf/build
+/examples/perf/data
+
+# /examples/pre-acknowledge/
+/examples/pre-acknowledge/build
+/examples/pre-acknowledge/logs
+
+# /examples/pre-acknowledge/server0/
+/examples/pre-acknowledge/server0/data
+/examples/pre-acknowledge/server0/logs
+
+# /examples/producer-rate-limit/
+/examples/producer-rate-limit/build
+/examples/producer-rate-limit/logs
+
+# /examples/producer-rate-limit/server0/
+/examples/producer-rate-limit/server0/data
+/examples/producer-rate-limit/server0/logs
+
+# /examples/queue/
+/examples/queue/build
+/examples/queue/logs
+
+# /examples/queue/server0/
+/examples/queue/server0/data
+/examples/queue/server0/logs
+
+# /examples/queue-message-redistribution/
+/examples/queue-message-redistribution/build
+/examples/queue-message-redistribution/logs
+
+# /examples/queue-message-redistribution/server0/
+/examples/queue-message-redistribution/server0/data
+/examples/queue-message-redistribution/server0/logs
+
+# /examples/queue-message-redistribution/server1/
+/examples/queue-message-redistribution/server1/data
+/examples/queue-message-redistribution/server1/logs
+
+# /examples/queue-requestor/
+/examples/queue-requestor/build
+/examples/queue-requestor/logs
+
+# /examples/queue-requestor/server0/
+/examples/queue-requestor/server0/data
+/examples/queue-requestor/server0/logs
+
+# /examples/queue-selector/
+/examples/queue-selector/build
+/examples/queue-selector/logs
+
+# /examples/queue-selector/server0/
+/examples/queue-selector/server0/data
+/examples/queue-selector/server0/logs
+
+# /examples/reattach-node/
+/examples/reattach-node/build
+/examples/reattach-node/logs
+
+# /examples/reattach-node/server0/
+/examples/reattach-node/server0/data
+/examples/reattach-node/server0/logs
+
+# /examples/request-reply/
+/examples/request-reply/build
+/examples/request-reply/logs
+
+# /examples/request-reply/server0/
+/examples/request-reply/server0/data
+/examples/request-reply/server0/logs
+
+# /examples/scheduled-message/
+/examples/scheduled-message/build
+/examples/scheduled-message/logs
+
+# /examples/scheduled-message/server0/
+/examples/scheduled-message/server0/data
+/examples/scheduled-message/server0/logs
+
+# /examples/security/
+/examples/security/build
+/examples/security/logs
+
+# /examples/security/server0/
+/examples/security/server0/data
+/examples/security/server0/logs
+
+# /examples/send-acknowledgements/
+/examples/send-acknowledgements/build
+/examples/send-acknowledgements/logs
+
+# /examples/send-acknowledgements/server0/
+/examples/send-acknowledgements/server0/data
+/examples/send-acknowledgements/server0/logs
+
+# /examples/ssl-enabled/
+/examples/ssl-enabled/build
+/examples/ssl-enabled/logs
+
+# /examples/ssl-enabled/server0/
+/examples/ssl-enabled/server0/data
+/examples/ssl-enabled/server0/logs
+
+# /examples/static-selector/
+/examples/static-selector/build
+/examples/static-selector/logs
+
+# /examples/static-selector/server0/
+/examples/static-selector/server0/data
+/examples/static-selector/server0/logs
+
+# /examples/static-selector-jms/
+/examples/static-selector-jms/logs
+/examples/static-selector-jms/build
+
+# /examples/static-selector-jms/server0/
+/examples/static-selector-jms/server0/data
+/examples/static-selector-jms/server0/logs
+
+# /examples/stomp/
+/examples/stomp/build
+
+# /examples/stomp/server0/
+/examples/stomp/server0/data
+
+# /examples/symmetric-cluster/
+/examples/symmetric-cluster/build
+/examples/symmetric-cluster/logs
+
+# /examples/symmetric-cluster/server0/
+/examples/symmetric-cluster/server0/data
+/examples/symmetric-cluster/server0/logs
+
+# /examples/symmetric-cluster/server1/
+/examples/symmetric-cluster/server1/data
+/examples/symmetric-cluster/server1/logs
+
+# /examples/symmetric-cluster/server2/
+/examples/symmetric-cluster/server2/data
+/examples/symmetric-cluster/server2/logs
+
+# /examples/symmetric-cluster/server3/
+/examples/symmetric-cluster/server3/data
+/examples/symmetric-cluster/server3/logs
+
+# /examples/symmetric-cluster/server4/
+/examples/symmetric-cluster/server4/data
+/examples/symmetric-cluster/server4/logs
+
+# /examples/symmetric-cluster/server5/
+/examples/symmetric-cluster/server5/data
+/examples/symmetric-cluster/server5/logs
+
+# /examples/temp-queue/
+/examples/temp-queue/build
+/examples/temp-queue/logs
+
+# /examples/temp-queue/server0/
+/examples/temp-queue/server0/data
+/examples/temp-queue/server0/logs
+
+# /examples/topic/
+/examples/topic/build
+/examples/topic/logs
+
+# /examples/topic/server0/
+/examples/topic/server0/data
+/examples/topic/server0/logs
+
+# /examples/topic-hierarchies/
+/examples/topic-hierarchies/build
+/examples/topic-hierarchies/logs
+
+# /examples/topic-hierarchies/server0/
+/examples/topic-hierarchies/server0/data
+/examples/topic-hierarchies/server0/logs
+
+# /examples/topic-selector-example1/
+/examples/topic-selector-example1/build
+/examples/topic-selector-example1/logs
+
+# /examples/topic-selector-example1/server0/
+/examples/topic-selector-example1/server0/data
+/examples/topic-selector-example1/server0/logs
+
+# /examples/topic-selector-example2/
+/examples/topic-selector-example2/build
+/examples/topic-selector-example2/logs
+
+# /examples/topic-selector-example2/server0/
+/examples/topic-selector-example2/server0/data
+/examples/topic-selector-example2/server0/logs
+
+# /examples/transaction-failover/
+/examples/transaction-failover/build
+
+# /examples/transaction-failover/server0/
+/examples/transaction-failover/server0/data
+
+# /examples/transaction-failover/server1/
+/examples/transaction-failover/server1/data
+
+# /examples/transactional/
+/examples/transactional/build
+/examples/transactional/logs
+
+# /examples/transactional/server0/
+/examples/transactional/server0/data
+/examples/transactional/server0/logs
+
+# /examples/xa-heuristic/
+/examples/xa-heuristic/build
+/examples/xa-heuristic/logs
+
+# /examples/xa-heuristic/server0/
+/examples/xa-heuristic/server0/data
+/examples/xa-heuristic/server0/logs
+
+# /examples/xa-receive/
+/examples/xa-receive/build
+/examples/xa-receive/logs
+
+# /examples/xa-receive/server0/
+/examples/xa-receive/server0/data
+/examples/xa-receive/server0/logs
+
+# /examples/xa-send/
+/examples/xa-send/build
+/examples/xa-send/logs
+
+# /examples/xa-send/server0/
+/examples/xa-send/server0/data
+/examples/xa-send/server0/logs
+
+# /examples/xa-with-jta/
+/examples/xa-with-jta/server0/data
+/examples/xa-with-jta/build
+/examples/xa-with-jta/logs
+/examples/xa-with-jta/ObjectStore
+
+# /examples/xa-with-jta/server0/
+/examples/xa-with-jta/server0/data
+/examples/xa-with-jta/server0/logs
+
+# examples/browser/data/
+examples/browser/data/
+
+# examples/client-kickoff/data/
+examples/client-kickoff/data/
+
+# examples/consumer-rate-limit/data/
+examples/consumer-rate-limit/data/
+
+# examples/data/
+examples/data/
+
+# examples/dead-letter/data/
+examples/dead-letter/data/
+
+# examples/delayed-redelivery/data/
+examples/delayed-redelivery/data/
+
+# examples/durable-subscription/data/
+examples/durable-subscription/data/
+
+# examples/expiry/data/
+examples/expiry/data/
+
+# examples/http-transport/data/
+examples/http-transport/data/
+
+# examples/instantiate-connection-factory/data/
+examples/instantiate-connection-factory/data/
+
+# examples/interceptor/data/
+examples/interceptor/data/
+
+# examples/jaas/data/
+examples/jaas/data/
+
+# examples/jmx/data/
+examples/jmx/data/
+
+examples/move.sh
+examples/move2.sh
+examples/pom-template.xml
+
+# /examples/soak/normal/
+/examples/soak/normal/build
+
+# /examples/soak/tx-restarts/
+/examples/soak/tx-restarts/build
+
+# /hornetq-protocols/
+/hornetq-protocols/hornetq-amqp-protocol/.project
+/hornetq-protocols/hornetq-stomp-protocol/.project
+
+# /hornetq-ra/hornetq-ra-jar/
+/hornetq-ra/hornetq-ra-jar/target
+/hornetq-ra/hornetq-ra-jar/.project
+
+# /hornetq-ra/hornetq-ra-rar/
+/hornetq-ra/hornetq-ra-rar/target
+/hornetq-ra/hornetq-ra-rar/.project
+
+# /hornetq-rest/hornetq-rest/
+/hornetq-rest/target
+/hornetq-rest/.project
+/hornetq-rest/data/
+
+# /hornetq-rest/
+/hornetq-*/.project
+/hornetq-*/target
+
+/tests/.project
+/tests/*-tests/.project
+
+/docs/rest-manual/.project
+/docs/quickstart-guide/.project
+
+native/autom4te.cache
+native/src/.libs
+native/src/.deps
+.settings/org.eclipse.core.resources.prefs
+
+*.iml
+*/*.iml
+*/*/*.iml
+*/*/*/*.iml
+
+hornetq.log
+*/hornetq.log
+*/*/hornetq.log
+*/*/*/hornetq.log
diff --git a/.project b/.project
new file mode 100644
index 0000000000..d928224b6f
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ hornetq
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/.settings/de.loskutov.anyedit.AnyEditTools.prefs b/.settings/de.loskutov.anyedit.AnyEditTools.prefs
new file mode 100644
index 0000000000..6858acb592
--- /dev/null
+++ b/.settings/de.loskutov.anyedit.AnyEditTools.prefs
@@ -0,0 +1,14 @@
+activeContentFilterList=*.makefile,makefile,*.Makefile,Makefile,Makefile.*,*.mk,MANIFEST.MF
+convertActionOnSaave=AnyEdit.CnvrtTabToSpaces
+eclipse.preferences.version=1
+inActiveContentFilterList=
+javaTabWidthForJava=true
+org.eclipse.jdt.ui.editor.tab.width=3
+projectPropsEnabled=true
+removeTrailingSpaces=true
+replaceAllSpaces=false
+replaceAllTabs=false
+saveAndAddLine=false
+saveAndConvert=true
+saveAndTrim=true
+useModulo4Tabs=false
diff --git a/.settings/intellij_settings.jar b/.settings/intellij_settings.jar
new file mode 100644
index 0000000000..4a3bf10fcc
Binary files /dev/null and b/.settings/intellij_settings.jar differ
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000000..288a13f562
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,14 @@
+HornetQ
+Copyright 2009 Red Hat, Inc. Licensed under the Apache License, version 2.0.
+Unless required by applicable law, HornetQ is distributed on
+an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, either express or
+implied, including the implied warranties of TITLE, NON-INFRINGEMENT,
+MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
+
+Certain portions of HornetQ are based on code made available
+under the GNU Lesser General Public License, version 2.1 or later
+(http://www.fsf.org/licensing/licenses/lgpl.html).
+"JBoss" and "Red Hat" are trademarks of Red Hat, Inc. and/or its
+affiliates, registered in the U.S. and other countries. Your
+permissions under the licensing terms governing HornetQ do
+not include a license, express or implied, to any Red Hat trademark.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..d37b3a5354
--- /dev/null
+++ b/README.md
@@ -0,0 +1,171 @@
+# HornetQ
+
+If you need information about the HornetQ project please go to
+
+http://community.jboss.org/wiki/HornetQ
+
+http://www.jboss.org/hornetq/
+
+This file describes some minimum 'stuff one needs to know' to get
+started coding in this project.
+
+## Source
+
+The project's source code is hosted at:
+
+https://github.com/hornetq
+
+### Git usage:
+
+Pull requests should be merged without fast forwards '--no-ff'. An easy way to achieve that is to use
+
+```% git config branch.master.mergeoptions --no-ff```
+
+## Maven
+
+The minimum required Maven version is 3.0.0.
+
+Do note that there are some compatibility issues with Maven 3.X still
+unsolved [1]. This is specially true for the 'site' plugin [2].
+
+[1]:
+[2]:
+
+## Tests
+
+To run the unit tests:
+
+```% mvn -Phudson-tests test```
+
+Generating reports from unit tests:
+
+```% mvn install site```
+
+
+Running tests individually
+
+```% mvn -Phudson-tests -DfailIfNoTests=false -Dtest= test ```
+
+where <test-name> is the name of the Test class without its package name
+
+
+## Examples
+
+To run an example firstly make sure you have run
+
+```% mvn -Prelease install```
+
+If the project version has already been released then this is unnecessary.
+
+then you will need to set the following maven options, on Linux by
+
+```export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=512m"```
+
+and the finally run the examples by
+
+```% mvn verify```
+
+You can also run individual examples by running the same command from the directory of which ever example you want to run.
+NB for this make sure you have installed examples/common.
+
+### Recreating the examples
+
+If you are trying to copy the examples somewhere else and modifying them. Consider asking Maven to explicitly list all the dependencies:
+
+```
+# if trying to modify the 'topic' example:
+cd examples/jms/topic && mvn dependency:list
+```
+
+## To build a release artifact
+
+```% mvn -Prelease install```
+
+## To build the release bundle
+
+```% mvn -Prelease package```
+
+## Eclipse
+
+We recommend using Eclipse Kepler (4.3), due to the built-in support
+for Maven and Git. Note that there are still some Maven plugins used
+by sub-projects (e.g. documentation) which are not supported even in
+Eclipse Kepler (4.3).
+
+Eclipse [m2e] is already included in "Eclipse IDE for Java Developers", or it
+can be installed from [Eclipse Kepler release repository].
+
+[m2e]: http://eclipse.org/m2e/
+[Eclipse Kepler release repository]: http://download.eclipse.org/releases/kepler
+
+### Annotation Pre-Processing
+
+HornetQ uses [JBoss Logging] and that requires source code generation from Java
+annotations. In order for it to 'just work' in Eclipse you need to install the
+_Maven Integration for Eclipse JDT Annotation Processor Toolkit_ [m2e-apt]. See
+this [JBoss blog post] for details.
+
+[JBoss Logging]:
+[m2e-apt]: https://github.com/jbosstools/m2e-apt
+[JBoss blog post]: https://community.jboss.org/en/tools/blog/2012/05/20/annotation-processing-support-in-m2e-or-m2e-apt-100-is-out
+
+### M2E Connector for Javacc-Maven-Plugin
+
+Eclipse Indigo (3.7) has out-of-the-box support for it.
+
+As of this writing, Eclipse Kepler (4.3) still lacks support for
+Maven's javacc plugin. The available [m2e connector for
+javacc-maven-plugin] requires a downgrade of Maven components to be
+installed. manual installation instructions (as of this writing you
+need to use the development update site). See [this post] for how to
+do this with Eclipse Juno (4.2).
+
+The current recommended solution for Eclipse Kepler is to mark
+`javacc-maven-plugin` as ignored by Eclipse, run Maven from the
+command line and then modify the project `hornetq-core-client` adding
+the folder `target/generated-sources/javacc` to its build path.
+
+[m2e connector for javacc-maven-plugin]: https://github.com/objectledge/maven-extensions
+[this post]:
+http://dev.eclipse.org/mhonarc/lists/m2e-users/msg02725.html
+
+### Use _Project Working Sets_
+
+Importing all HornetQ subprojects will create _too many_ projects in Eclipse,
+cluttering your _Package Explorer_ and _Project Explorer_ views. One way to address
+that is to use [Eclipse's Working Sets] feature. A good introduction to it can be
+found at a [Dzone article on Eclipse Working Sets].
+
+[Eclipse's Working Sets]: http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.user%2Fconcepts%2Fcworkset.htm
+[Dzone article on Eclipse Working Sets]: http://eclipse.dzone.com/articles/categorise-projects-package
+
+### Code Formatting
+
+Eclipse code formatting and (basic) project configuration files can be found at
+the ```etc/``` folder. You should manually copy them _after importing all your
+projects_:
+
+```
+for settings_dir in `find . -type d -name .settings`; do
+ \cp -v etc/org.eclipse.jdt.* $settings_dir
+done
+```
+
+Do not use the [maven-eclipse-plugin] to copy the files as it conflicts with [m2e].
+
+[maven-eclipse-plugin]: https://maven.apache.org/plugins/maven-eclipse-plugin/
+[m2e]: http://eclipse.org/m2e/
+
+## GitHub procedures
+
+The best way to submit changes to HornetQ is through pull requests on
+GitHub. After review a pull request should either get merged or be
+rejected.
+
+When a pull request needs to be reworked, say you have missed
+something, the pull request is then closed. When you finished
+addressing the required changes you should reopen your original pull
+request and it will then be re-evaluated. At that point if the request
+is approved we will then merge it.
+
+Make sure you always rebase your branch on master before submitting pull requests.
diff --git a/RELEASING.md b/RELEASING.md
new file mode 100644
index 0000000000..1f839877e9
--- /dev/null
+++ b/RELEASING.md
@@ -0,0 +1,61 @@
+# A check list of things to be done before a release. #
+
+Things to do before issuing a new MAJOR release:
+
+* check if all new Configuration parameters are documented;
+
+* use your IDE to regenerate equals/hashCode for ConfigurationImpl (this
+ is just much safer than trying to inspect the code).
+
+* check if all public API classes have a proper Javadoc.
+
+
+## Tagging a release in Git ##
+
+We must avoid having multiple commits with the same final release version in the POMs. To achieve that, the commit changing the pom versions to the final release version, should be merged together with a second commit changing to version in all pom's to ``X.Y.Z-SNAPSHOT``.
+
+Assuming current version is ``X.Y.Z-SNAPSHOT``
+
+0. Update the release notes.
+1. Prepare a single commit changing all version tags in all pom's.
+2. tag this commit locally by 'git tag -a HornetQ_X_Y_Z_Final -m "release for x.y.z.Final' or what ever the version is
+3. remember to update the version in the main pom, think of a cool name if you can
+4. update the hornetq-maven-plugin plugin in the main pom to one that is released, if needed release a new version of the plugin.
+5. Either use ``git revert`` to create a new commit reverting the commit with the version changes. Or change again all versions to ``R.S.T-SNAPSHOT``.
+6. push both commits with version changes together, including them in the same _pull-request_.
+7. push the committed tag upstream 'git push upstream HornetQ_X_Y_Z_Final'
+8. download and unpack the tag from github
+9. firstly upload the maven artifacts to the staged repository 'mvn -Pmaven-release deploy' (you will need the repository details in your settings.xml'
+10. go to nexus (https://repository.jboss.org/nexus/index.html), log in, select staging repositories, select the staging profile that you uploaded and close it.
+11. build the standalone release 'mvn -Prelease package' to build the zip and tar.gz
+
+testing the standalone release (this should be done on windows as well as linux if possible)
+
+1. unpack the zip or tar.gz
+2. start and stop the server (run.sh and stop.sh) for each configuration
+3. run the jms examples (follow the instructions under examples/jms/README.md), if you have a failure (memory etc) you can use mvn -rf to restart
+4. run the javaee examples (follow instructions under examples/javaee/README.md)
+5. check the manuals have been created properly
+6. check the javadocs are created correctly (including the diagrams)
+
+testing the release for AS7
+
+1. update the hornetq version in you local AS7 clone (there may be integration work you may have to include that is in the hornetq AS7 clone)
+2. commit this and push to your repo
+3. go to http://lightning.mw.lab.eng.bos.redhat.com/jenkins/job/as7-param-all-tests/ and run against your repo (using the staged repo).
+4. go to http://lightning.mw.lab.eng.bos.redhat.com/jenkins/job/tck6-as7-jms/ and run against your repo (using the staged repo). (note this takes 5 hours)
+
+If everything is ok then release by:
+
+1. Upload the binaries and docs to jboss.org (instructions can be found at https://mojo.redhat.com/docs/DOC-81955)
+2. go to https://www.jboss.org/author/.magnolia/pages/adminCentral.html and update the download/docs pages and add a release announcement if needed.
+3. when you are happy activate the changes
+4. go to nexus and release the maven artifacts from the staging repository
+5. do announcements twitter/blog
+
+if there is a problem
+
+1. delete the tag locally 'git tag -d HornetQ_X_Y_Z_Final"
+2. delete the tag remotely 'git push origin :refs/tags/HornetQ_X_Y_Z_Final"
+3. go to nexus and drop the profile
+4. fix what's broken and start again
diff --git a/distribution/hornetq/pom.xml b/distribution/hornetq/pom.xml
new file mode 100644
index 0000000000..644b6b4d72
--- /dev/null
+++ b/distribution/hornetq/pom.xml
@@ -0,0 +1,186 @@
+
+
+
+ 4.0.0
+
+
+
+ org.hornetq
+ hornetq-distribution
+ 2.5.0-SNAPSHOT
+
+
+ hornetq
+ pom
+ Actual HornetQ Distribution
+
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-bin/${project.artifactId}-${project.version}/schema
+ src/main/resources/config/stand-alone
+ src/main/resources/config/jboss-as-6
+
+
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-amqp-protocol
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-stomp-protocol
+ ${project.version}
+
+
+ org.apache.qpid
+ proton-api
+
+
+ org.apache.qpid
+ proton-j-impl
+
+
+ org.apache.qpid
+ proton-jms
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+ maven-assembly-plugin
+ 2.2
+
+ src/main/assembly/dep.xml
+ gnu
+
+
+
+ package
+
+ single
+
+
+
+
+
+ org.codehaus.mojo
+ xml-maven-plugin
+
+
+ package
+
+ validate
+
+
+
+
+
+
+ ${standalone}/clustered
+ ${schemaLocation}/hornetq-configuration.xsd
+
+ hornetq-configuration.xml
+
+
+
+ ${standalone}/non-clustered
+ ${schemaLocation}/hornetq-configuration.xsd
+
+ hornetq-configuration.xml
+
+
+
+ ${as6}/clustered
+ ${schemaLocation}/hornetq-configuration.xsd
+
+ hornetq-configuration.xml
+
+
+
+ ${as6}/non-clustered
+ ${schemaLocation}/hornetq-configuration.xsd
+
+ hornetq-configuration.xml
+
+
+
+ ${standalone}/clustered
+ ${schemaLocation}/hornetq-jms.xsd
+
+ hornetq-jms.xml
+
+
+
+ ${standalone}/non-clustered
+ ${schemaLocation}/hornetq-jms.xsd
+
+ hornetq-jms.xml
+
+
+
+ ${as6}/clustered
+ ${schemaLocation}/hornetq-jms.xsd
+
+ hornetq-jms.xml
+
+
+
+ ${as6}/non-clustered
+ ${schemaLocation}/hornetq-jms.xsd
+
+ hornetq-jms.xml
+
+
+
+ ${standalone}/clustered
+ ${schemaLocation}/hornetq-users.xsd
+
+ hornetq-users.xml
+
+
+
+ ${standalone}/non-clustered
+ ${schemaLocation}/hornetq-users.xsd
+
+ hornetq-users.xml
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/assembly/dep.xml b/distribution/hornetq/src/main/assembly/dep.xml
new file mode 100644
index 0000000000..f2ee1d1c99
--- /dev/null
+++ b/distribution/hornetq/src/main/assembly/dep.xml
@@ -0,0 +1,508 @@
+
+
+
+
+ bin
+
+ dir
+ zip
+ tar.gz
+
+ true
+
+
+ true
+
+ org.hornetq:hornetq-commons
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-journal
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-native
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-tools
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-bootstrap
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-server
+
+
+ false
+
+ true
+
+
+ **/*.xsd
+
+
+
+
+
+ true
+
+ org.hornetq:hornetq-native
+
+
+ false
+ bin
+ true
+
+
+ **/*.so
+
+
+
+
+
+ true
+
+ org.hornetq:hornetq-core-client
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-server
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-jboss-as-integration
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-jms-client
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-jms-server
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-jms-server
+
+
+ false
+
+ true
+
+
+ **/*.xsd
+
+
+
+
+
+ true
+
+ org.hornetq:hornetq-jms-client
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-ra
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-service-sar
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-spring-integration
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-twitter-integration
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-vertx-integration
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq.rest:hornetq-rest
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-amqp-protocol
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-aerogear-integration
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-stomp-protocol
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-selector
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:jnp-client
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:jboss-mc
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:jboss-mc
+
+
+ false
+ lib
+ false
+ ${module.artifactId}.${module.extension}
+
+
+
+ true
+
+ org.hornetq:hornetq-core-client
+
+
+ javadoc
+ false
+ docs/api/hornetq-client
+
+
+
+ true
+
+ org.hornetq:hornetq-server
+
+
+ javadoc
+ false
+ docs/api/hornetq-server
+
+
+
+ true
+
+ org.hornetq:hornetq-jms-client
+
+
+ javadoc
+ false
+ docs/api/hornetq-jms-client
+
+
+
+ true
+
+ org.hornetq:hornetq-jms-server
+
+
+ javadoc
+ false
+ docs/api/hornetq-jms-server
+
+
+
+
+
+
+ org.jboss.spec.javax.jms:jboss-jms-api_2.0_spec
+
+ lib
+ false
+ jboss-jms-api.jar
+
+
+
+ org.jboss.naming:jnpserver
+
+ lib
+ false
+ jnpserver.jar
+
+
+
+ io.netty:netty-all
+
+ lib
+ false
+ netty.jar
+
+
+
+ org.apache.qpid:proton-api
+
+ lib
+ false
+ proton-api.jar
+
+
+
+ org.apache.qpid:proton-jms
+
+ lib
+ false
+ proton-jms.jar
+
+
+
+ org.apache.qpid:proton-j-impl
+
+ lib
+ false
+ proton-j-impl.jar
+
+
+
+
+ src/main/resources/config
+ config
+ keep
+
+ **/trunk/**
+ *.properties
+
+
+
+ src/main/resources/bin
+ bin
+ keep
+
+
+ src/main/resources/licenses
+ licenses
+ keep
+
+
+ src/main/resources/examples
+ examples
+ keep
+
+
+ ../../examples
+ examples
+ keep
+
+ **/target/**
+ **/**/*.iml
+ **/**/*.dat
+
+
+
+
+ ../../docs/user-manual/target/docbook/publish/en
+ docs/user-manual
+ keep
+
+
+ ../../docs/quickstart-guide/target/docbook/publish/en
+ docs/quickstart-guide
+ keep
+
+
+ ../../docs/rest-manual/target/docbook/publish/en
+ docs/rest-manual
+ keep
+
+
+
diff --git a/distribution/hornetq/src/main/resources/bin/run.bat b/distribution/hornetq/src/main/resources/bin/run.bat
new file mode 100644
index 0000000000..0772410a56
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/bin/run.bat
@@ -0,0 +1,21 @@
+@ echo off
+setlocal ENABLEDELAYEDEXPANSION
+set HORNETQ_HOME=..
+IF "a%1"== "a" (
+set CONFIG_DIR=%HORNETQ_HOME%\config\stand-alone\non-clustered
+) ELSE (
+SET CONFIG_DIR=%1
+)
+set CLASSPATH=%CONFIG_DIR%;%HORNETQ_HOME%\schemas\
+REM you can use the following line if you want to run with different ports
+REM set CLUSTER_PROPS="-Djnp.port=1099 -Djnp.rmiPort=1098 -Djnp.host=localhost -Dhornetq.remoting.netty.host=localhost -Dhornetq.remoting.netty.port=5445"
+set JVM_ARGS=%CLUSTER_PROPS% -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -Xms512M -Xmx1024M -Dhornetq.config.dir=%CONFIG_DIR% -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Djava.util.logging.config.file=%CONFIG_DIR%\logging.properties -Djava.library.path=.
+REM export JVM_ARGS="-Xmx512M -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Djava.util.logging.config.file=%CONFIG_DIR%\logging.properties -Dhornetq.config.dir=$CONFIG_DIR -Djava.library.path=. -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"
+for /R ..\lib %%A in (*.jar) do (
+SET CLASSPATH=!CLASSPATH!;%%A
+)
+mkdir ..\logs
+echo ***********************************************************************************
+echo "java %JVM_ARGS% -classpath %CLASSPATH% org.hornetq.integration.bootstrap.HornetQBootstrapServer hornetq-beans.xml"
+echo ***********************************************************************************
+java %JVM_ARGS% -classpath "%CLASSPATH%" org.hornetq.integration.bootstrap.HornetQBootstrapServer hornetq-beans.xml
diff --git a/distribution/hornetq/src/main/resources/bin/run.sh b/distribution/hornetq/src/main/resources/bin/run.sh
new file mode 100755
index 0000000000..87e5aa869c
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/bin/run.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+#------------------------------------------------
+# Simple shell-script to run HornetQ standalone
+#------------------------------------------------
+
+export HORNETQ_HOME=..
+mkdir -p ../logs
+
+# By default, the server is started in the non-clustered standalone configuration
+
+if [ a"$1" = a ]; then CONFIG_DIR=$HORNETQ_HOME/config/stand-alone/non-clustered; else CONFIG_DIR="$1"; fi
+if [ a"$2" = a ]; then FILENAME=hornetq-beans.xml; else FILENAME="$2"; fi
+
+if [ ! -d $CONFIG_DIR ]; then
+ echo script needs to be run from the HORNETQ_HOME/bin directory >&2
+ exit 1
+fi
+
+RESOLVED_CONFIG_DIR=`cd "$CONFIG_DIR"; pwd`
+export CLASSPATH=$RESOLVED_CONFIG_DIR:$HORNETQ_HOME/schemas/
+
+# Use the following line to run with different ports
+#export CLUSTER_PROPS="-Djnp.port=1099 -Djnp.rmiPort=1098 -Djnp.host=localhost -Dhornetq.remoting.netty.host=localhost -Dhornetq.remoting.netty.port=5445"
+
+export JVM_ARGS="$CLUSTER_PROPS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -Xms512M -Xmx1024M -Dhornetq.config.dir=$RESOLVED_CONFIG_DIR -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Dlogging.configuration=file://$RESOLVED_CONFIG_DIR/logging.properties -Djava.library.path=./lib/linux-i686:./lib/linux-x86_64"
+#export JVM_ARGS="-Xmx512M -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Dlogging.configuration=$CONFIG_DIR/logging.properties -Dhornetq.config.dir=$CONFIG_DIR -Djava.library.path=. -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"
+
+for i in `ls $HORNETQ_HOME/lib/*.jar`; do
+ CLASSPATH=$i:$CLASSPATH
+done
+
+echo "***********************************************************************************"
+echo "java $JVM_ARGS -classpath $CLASSPATH org.hornetq.integration.bootstrap.HornetQBootstrapServer $FILENAME"
+echo "***********************************************************************************"
+java $JVM_ARGS -classpath $CLASSPATH -Dcom.sun.management.jmxremote org.hornetq.integration.bootstrap.HornetQBootstrapServer $FILENAME
diff --git a/distribution/hornetq/src/main/resources/bin/stop.bat b/distribution/hornetq/src/main/resources/bin/stop.bat
new file mode 100644
index 0000000000..4a1aa8eb41
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/bin/stop.bat
@@ -0,0 +1,9 @@
+@ echo off
+setlocal ENABLEDELAYEDEXPANSION
+set HORNETQ_HOME=..
+IF "a%1"== "a" (
+set CONFIG_DIR=%HORNETQ_HOME%\config\stand-alone\non-clustered
+) ELSE (
+SET CONFIG_DIR=%1
+)
+dir >> %CONFIG_DIR%\STOP_ME
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/bin/stop.sh b/distribution/hornetq/src/main/resources/bin/stop.sh
new file mode 100755
index 0000000000..9f5524897f
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/bin/stop.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+export HORNETQ_HOME=..
+if [ a"$1" = a ]; then CONFIG_DIR=$HORNETQ_HOME/config/stand-alone/non-clustered; else CONFIG_DIR="$1"; fi
+touch $CONFIG_DIR/STOP_ME;
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-configuration.xml
new file mode 100644
index 0000000000..fb54135088
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-configuration.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+ HornetQ.main.config
+
+ ${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/bindings
+
+ ${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/journal
+
+ 10
+
+ ${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/largemessages
+
+ ${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/paging
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory
+
+
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 5000
+ netty
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 10000
+
+
+
+
+
+ jms
+ netty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-jboss-beans.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-jboss-beans.xml
new file mode 100644
index 0000000000..50768e0c06
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-jboss-beans.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${jboss.server.home.url}/deploy/hornetq/hornetq-configuration.xml
+
+
+
+
+
+
+ JBossSecurityJNDIContextEstablishment
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jboss.jca:name='jms-ra.rar',service=RARDeployment
+
+ HornetQServer
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-jms.xml
new file mode 100644
index 0000000000..8d4bd7af8a
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/hornetq-jms.xml
@@ -0,0 +1,47 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/jms-ds.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/jms-ds.xml
new file mode 100644
index 0000000000..f387cf9efb
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/clustered/jms-ds.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ DefaultJMSProvider
+ org.jboss.jms.jndi.JNDIProviderAdapter
+ java:/XAConnectionFactory
+ java:/XAConnectionFactory
+ java:/XAConnectionFactory
+
+
+
+ JmsXA
+
+ jms-ra.rar
+ org.hornetq.ra.HornetQRAConnectionFactory
+ javax.jms.Topic
+ java:/DefaultJMSProvider
+ 20
+ JmsXARealm
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-configuration.xml
new file mode 100644
index 0000000000..a92796f3f0
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-configuration.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+ HornetQ.main.config
+
+ ${jboss.server.data.dir}/hornetq/bindings
+
+ ${jboss.server.data.dir}/hornetq/journal
+
+ 10
+
+ ${jboss.server.data.dir}/hornetq/largemessages
+
+ ${jboss.server.data.dir}/hornetq/paging
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-jboss-beans.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-jboss-beans.xml
new file mode 100644
index 0000000000..238792c3f3
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-jboss-beans.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${jboss.server.home.url}/deploy/hornetq/hornetq-configuration.xml
+
+
+
+
+
+
+ JBossSecurityJNDIContextEstablishment
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jboss.jca:name='jms-ra.rar',service=RARDeployment
+
+ HornetQServer
+
+
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-jms.xml
new file mode 100644
index 0000000000..8fcc22798a
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/hornetq-jms.xml
@@ -0,0 +1,46 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/jms-ds.xml b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/jms-ds.xml
new file mode 100644
index 0000000000..f387cf9efb
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/jboss-as-6/non-clustered/jms-ds.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ DefaultJMSProvider
+ org.jboss.jms.jndi.JNDIProviderAdapter
+ java:/XAConnectionFactory
+ java:/XAConnectionFactory
+ java:/XAConnectionFactory
+
+
+
+ JmsXA
+
+ jms-ra.rar
+ org.hornetq.ra.HornetQRAConnectionFactory
+ javax.jms.Topic
+ java:/DefaultJMSProvider
+ 20
+ JmsXARealm
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-beans.xml
new file mode 100644
index 0000000000..423c8cb6fc
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-beans.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${jnp.port:1099}
+ ${jnp.host:localhost}
+ ${jnp.rmiPort:1098}
+ ${jnp.host:localhost}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-configuration.xml
new file mode 100644
index 0000000000..474d507616
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-configuration.xml
@@ -0,0 +1,94 @@
+
+
+ ${data.dir:../data}/paging
+
+ ${data.dir:../data}/bindings
+
+ ${data.dir:../data}/journal
+
+ 10
+
+ ${data.dir:../data}/large-messages
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 5000
+ netty
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 10000
+
+
+
+
+
+ jms
+ netty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-jms.xml
new file mode 100644
index 0000000000..044d7e88ed
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-jms.xml
@@ -0,0 +1,53 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/clustered/jndi.properties b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/clustered/logging.properties b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/logging.properties
new file mode 100644
index 0000000000..3b725aff65
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/clustered/logging.properties
@@ -0,0 +1,56 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+# Root logger option
+loggers=org.jboss.logging,org.hornetq.core.server,org.hornetq.utils,org.hornetq.journal,org.hornetq.jms,org.hornetq.integration.bootstrap
+
+# Root logger level
+logger.level=INFO
+# HornetQ logger levels
+logger.org.hornetq.core.server.level=INFO
+logger.org.hornetq.journal.level=INFO
+logger.org.hornetq.utils.level=INFO
+logger.org.hornetq.jms.level=INFO
+logger.org.hornetq.integration.bootstrap.level=INFO
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=DEBUG
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=logs/hornetq.log
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-beans.xml
new file mode 100644
index 0000000000..2cbcb12b25
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-beans.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${jnp.port:1099}
+ ${jnp.host:localhost}
+ ${jnp.rmiPort:1098}
+ ${jnp.host:localhost}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-configuration.xml
new file mode 100644
index 0000000000..8b0922d344
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-configuration.xml
@@ -0,0 +1,67 @@
+
+
+ ${data.dir:../data}/paging
+
+ ${data.dir:../data}/bindings
+
+ ${data.dir:../data}/journal
+
+ 10
+
+ ${data.dir:../data}/large-messages
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-jms.xml
new file mode 100644
index 0000000000..044d7e88ed
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-jms.xml
@@ -0,0 +1,53 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/jndi.properties b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/logging.properties b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/logging.properties
new file mode 100644
index 0000000000..e9b25803da
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/non-clustered/logging.properties
@@ -0,0 +1,56 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+# Root logger option
+loggers=org.jboss.logging,org.hornetq.core.server,org.hornetq.utils,org.hornetq.journal,org.hornetq.jms,org.hornetq.integration.bootstrap
+
+# Root logger level
+logger.level=INFO
+# HornetQ logger levels
+logger.org.hornetq.core.server.level=INFO
+logger.org.hornetq.journal.level=INFO
+logger.org.hornetq.utils.level=INFO
+logger.org.hornetq.jms.level=INFO
+logger.org.hornetq.integration.bootstrap.level=INFO
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=FINE
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=FINE
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=logs/hornetq.log
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-beans.xml
new file mode 100644
index 0000000000..423c8cb6fc
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-beans.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${jnp.port:1099}
+ ${jnp.host:localhost}
+ ${jnp.rmiPort:1098}
+ ${jnp.host:localhost}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-configuration.xml
new file mode 100644
index 0000000000..5605f0069c
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-configuration.xml
@@ -0,0 +1,101 @@
+
+
+ false
+
+ ${hornetq.backup:false}
+
+ ${data.dir:../data}/paging
+
+ ${data.dir:../data}/bindings
+
+ ${data.dir:../data}/journal
+
+ 10
+
+ ${data.dir:../data}/large-messages
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 5000
+ netty
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 10000
+
+
+
+
+
+ jms
+ netty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-jms.xml
new file mode 100644
index 0000000000..044d7e88ed
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-jms.xml
@@ -0,0 +1,53 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/replicated/jndi.properties b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/replicated/logging.properties b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/logging.properties
new file mode 100644
index 0000000000..3b725aff65
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/replicated/logging.properties
@@ -0,0 +1,56 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+# Root logger option
+loggers=org.jboss.logging,org.hornetq.core.server,org.hornetq.utils,org.hornetq.journal,org.hornetq.jms,org.hornetq.integration.bootstrap
+
+# Root logger level
+logger.level=INFO
+# HornetQ logger levels
+logger.org.hornetq.core.server.level=INFO
+logger.org.hornetq.journal.level=INFO
+logger.org.hornetq.utils.level=INFO
+logger.org.hornetq.jms.level=INFO
+logger.org.hornetq.integration.bootstrap.level=INFO
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=DEBUG
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=logs/hornetq.log
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-beans.xml
new file mode 100644
index 0000000000..423c8cb6fc
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-beans.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${jnp.port:1099}
+ ${jnp.host:localhost}
+ ${jnp.rmiPort:1098}
+ ${jnp.host:localhost}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-configuration.xml
new file mode 100644
index 0000000000..dea7a7b19d
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-configuration.xml
@@ -0,0 +1,101 @@
+
+
+ true
+
+ ${hornetq.backup:false}
+
+ ${data.dir:../data}/paging
+
+ ${data.dir:../data}/bindings
+
+ ${data.dir:../data}/journal
+
+ 10
+
+ ${data.dir:../data}/large-messages
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 5000
+ netty
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 10000
+
+
+
+
+
+ jms
+ netty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-jms.xml
new file mode 100644
index 0000000000..044d7e88ed
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-jms.xml
@@ -0,0 +1,53 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/jndi.properties b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/logging.properties b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/logging.properties
new file mode 100644
index 0000000000..3b725aff65
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/stand-alone/shared-store/logging.properties
@@ -0,0 +1,56 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+# Root logger option
+loggers=org.jboss.logging,org.hornetq.core.server,org.hornetq.utils,org.hornetq.journal,org.hornetq.jms,org.hornetq.integration.bootstrap
+
+# Root logger level
+logger.level=INFO
+# HornetQ logger levels
+logger.org.hornetq.core.server.level=INFO
+logger.org.hornetq.journal.level=INFO
+logger.org.hornetq.utils.level=INFO
+logger.org.hornetq.jms.level=INFO
+logger.org.hornetq.integration.bootstrap.level=INFO
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=DEBUG
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=logs/hornetq.log
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-beans.xml
new file mode 100644
index 0000000000..9705de0151
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-beans.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${jnp.port:1199}
+ ${jnp.host:localhost}
+ ${jnp.rmiPort:1198}
+ ${jnp.host:localhost}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-configuration.xml
new file mode 100644
index 0000000000..f0a2dc2fea
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-configuration.xml
@@ -0,0 +1,88 @@
+
+
+
+
+ true
+
+ true
+
+ true
+
+ 10
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 5000
+ netty
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 60000
+
+
+
+
+
+ jms
+ netty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-jms.xml
new file mode 100644
index 0000000000..3346589ad9
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-jms.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/jndi.properties b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/jndi.properties
new file mode 100644
index 0000000000..629072e931
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/jndi.properties
@@ -0,0 +1,15 @@
+#
+# Copyright 2009 Red Hat, Inc.
+# Red Hat 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.
+#
+
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/logging.properties b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/logging.properties
new file mode 100644
index 0000000000..dd49eadadf
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered-backup/logging.properties
@@ -0,0 +1,34 @@
+############################################################
+# Default Logging Configuration File
+#
+# You can use a different file by specifying a filename
+# with the java.util.logging.config.file system property.
+# For example java -Djava.util.logging.config.file=myfile
+############################################################
+
+############################################################
+# Global properties
+############################################################
+
+# "handlers" specifies a comma separated list of log Handler
+# classes. These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# By default we only configure a ConsoleHandler, which will only
+# show messages at the INFO and above levels.
+handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
+java.util.logging.ConsoleHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+java.util.logging.FileHandler.level=INFO
+java.util.logging.FileHandler.pattern=logs/hornetq.log
+java.util.logging.FileHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+# Default global logging level.
+# This specifies which kinds of events are logged across
+# all loggers. For any given facility this global level
+# can be overriden by a facility specific level
+# Note that the ConsoleHandler also has a separate level
+# setting to limit messages printed to the console.
+.level= INFO
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-beans.xml
new file mode 100644
index 0000000000..58afc780a5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-beans.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${jnp.port:1099}
+ ${jnp.host:localhost}
+ ${jnp.rmiPort:1098}
+ ${jnp.host:localhost}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-configuration.xml
new file mode 100644
index 0000000000..41fe395d12
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-configuration.xml
@@ -0,0 +1,73 @@
+
+
+ false
+
+ true
+
+ 10
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 5000
+ netty
+
+
+
+
+
+ 231.7.7.7
+ 9876
+ 60000
+
+
+
+
+
+ jms
+ netty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-jms.xml
new file mode 100644
index 0000000000..3346589ad9
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-jms.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered/jndi.properties b/distribution/hornetq/src/main/resources/config/trunk/clustered/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/clustered/logging.properties b/distribution/hornetq/src/main/resources/config/trunk/clustered/logging.properties
new file mode 100644
index 0000000000..dd49eadadf
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/clustered/logging.properties
@@ -0,0 +1,34 @@
+############################################################
+# Default Logging Configuration File
+#
+# You can use a different file by specifying a filename
+# with the java.util.logging.config.file system property.
+# For example java -Djava.util.logging.config.file=myfile
+############################################################
+
+############################################################
+# Global properties
+############################################################
+
+# "handlers" specifies a comma separated list of log Handler
+# classes. These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# By default we only configure a ConsoleHandler, which will only
+# show messages at the INFO and above levels.
+handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
+java.util.logging.ConsoleHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+java.util.logging.FileHandler.level=INFO
+java.util.logging.FileHandler.pattern=logs/hornetq.log
+java.util.logging.FileHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+# Default global logging level.
+# This specifies which kinds of events are logged across
+# all loggers. For any given facility this global level
+# can be overriden by a facility specific level
+# Note that the ConsoleHandler also has a separate level
+# setting to limit messages printed to the console.
+.level= INFO
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
diff --git a/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-beans.xml b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-beans.xml
new file mode 100644
index 0000000000..195019f2fd
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-beans.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-configuration.xml b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-configuration.xml
new file mode 100644
index 0000000000..d6788f3af5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-configuration.xml
@@ -0,0 +1,59 @@
+
+
+ 10
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ 10
+ BLOCK
+
+
+
+
diff --git a/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-jms.xml b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-jms.xml
new file mode 100644
index 0000000000..3a3dbeb697
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-jms.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-users.xml b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/non-clustered/jndi.properties b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/config/trunk/non-clustered/logging.properties b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/logging.properties
new file mode 100644
index 0000000000..00f9c3da5c
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/config/trunk/non-clustered/logging.properties
@@ -0,0 +1,38 @@
+############################################################
+# Default Logging Configuration File
+#
+# You can use a different file by specifying a filename
+# with the java.util.logging.config.file system property.
+# For example java -Djava.util.logging.config.file=myfile
+############################################################
+
+############################################################
+# Global properties
+############################################################
+
+# "handlers" specifies a comma separated list of log Handler
+# classes. These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# By default we only configure a ConsoleHandler, which will only
+# show messages at the INFO and above levels.
+handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
+java.util.logging.ConsoleHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+java.util.logging.FileHandler.level=INFO
+java.util.logging.FileHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+# cycle through 10 files of 20MiB max which append logs
+java.util.logging.FileHandler.count=10
+java.util.logging.FileHandler.limit=20971520
+java.util.logging.FileHandler.append=true
+java.util.logging.FileHandler.pattern=logs/hornetq.%g.log
+# Default global logging level.
+# This specifies which kinds of events are logged across
+# all loggers. For any given facility this global level
+# can be overriden by a facility specific level
+# Note that the ConsoleHandler also has a separate level
+# setting to limit messages printed to the console.
+.level= INFO
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
diff --git a/distribution/hornetq/src/main/resources/examples/common/config/ant.properties b/distribution/hornetq/src/main/resources/examples/common/config/ant.properties
new file mode 100644
index 0000000000..88ef1a7030
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/examples/common/config/ant.properties
@@ -0,0 +1,4 @@
+hornetq.example.logserveroutput=true
+hornetq.jars.dir=${imported.basedir}/../../lib
+jars.dir=${imported.basedir}/../../lib
+aio.library.path=${imported.basedir}/../../bin
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/licenses/LGPL.txt b/distribution/hornetq/src/main/resources/licenses/LGPL.txt
new file mode 100644
index 0000000000..9ef3d701d1
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/licenses/LGPL.txt
@@ -0,0 +1,503 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
diff --git a/distribution/hornetq/src/main/resources/licenses/LICENSE.txt b/distribution/hornetq/src/main/resources/licenses/LICENSE.txt
new file mode 100644
index 0000000000..7a4a3ea242
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/licenses/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/licenses/LICENSE_twitter4j.txt b/distribution/hornetq/src/main/resources/licenses/LICENSE_twitter4j.txt
new file mode 100644
index 0000000000..3a9829d611
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/licenses/LICENSE_twitter4j.txt
@@ -0,0 +1,26 @@
+Twitter4J includes software from JSON.org to parse JSON response from the Twitter API. You can see the license term at http://www.JSON.org/license.html
+
+Copyright (c) 2007-2010, Yusuke Yamamoto
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Yusuke Yamamoto nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY Yusuke Yamamoto ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL Yusuke Yamamoto BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/distribution/hornetq/src/main/resources/licenses/base64.txt b/distribution/hornetq/src/main/resources/licenses/base64.txt
new file mode 100644
index 0000000000..308461ba8a
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/licenses/base64.txt
@@ -0,0 +1,10 @@
+For org.hornetq.utils.Base64
+
+I am placing this code in the Public Domain. Do with it as you will.
+This software comes with no guarantees or warranties but with
+plenty of well-wishing instead!
+Please visit http://iharder.net/base64
+periodically to check for updates or to contribute improvements.
+
+@author Robert Harder
+@author rob@iharder.net
\ No newline at end of file
diff --git a/distribution/hornetq/src/main/resources/licenses/json.txt b/distribution/hornetq/src/main/resources/licenses/json.txt
new file mode 100644
index 0000000000..31b40d4b25
--- /dev/null
+++ b/distribution/hornetq/src/main/resources/licenses/json.txt
@@ -0,0 +1,23 @@
+For classes org.hornetq.utils.json.*
+
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/distribution/jboss-mc/pom.xml b/distribution/jboss-mc/pom.xml
new file mode 100644
index 0000000000..1a3fc0ae97
--- /dev/null
+++ b/distribution/jboss-mc/pom.xml
@@ -0,0 +1,123 @@
+
+ 4.0.0
+
+
+
+ org.hornetq
+ hornetq-distribution
+ 2.5.0-SNAPSHOT
+
+
+ jboss-mc
+ jar
+ JBoss Microcontainer jar
+
+
+
+
+ org.jboss.microcontainer
+ jboss-kernel
+
+
+ org.jboss.microcontainer
+ jboss-dependency
+
+
+ org.jboss
+ jboss-reflect
+
+
+ org.jboss
+ jboss-common-core
+
+
+ org.jboss
+ jboss-mdr
+
+
+ org.jboss
+ jbossxb
+
+
+ sun-jaxb
+ jaxb-api
+
+
+ org.jboss.logging
+ jboss-logging
+
+
+ org.jboss.logmanager
+ jboss-logmanager
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ org.jboss.netty:netty
+ org.jboss.logging:jboss-logging-spi
+
+
+
+
+
+ org.jboss.microcontainer:jboss-kernel
+
+
+ org.jboss.microcontainer:jboss-dependency
+
+
+ org.jboss:jboss-reflect
+
+
+ org.jboss:jboss-common-core
+
+
+ org.jboss:jboss-mdr
+
+
+ org.jboss:jbossxb
+
+
+ sun-jaxb:jaxb-api
+
+
+ org.jboss.logging:jboss-logging
+
+
+ org.jboss.logmanager:jboss-logmanager
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/jnp-client/pom.xml b/distribution/jnp-client/pom.xml
new file mode 100644
index 0000000000..896ec997ec
--- /dev/null
+++ b/distribution/jnp-client/pom.xml
@@ -0,0 +1,75 @@
+
+ 4.0.0
+
+
+
+ org.hornetq
+ hornetq-distribution
+ 2.5.0-SNAPSHOT
+
+
+ jnp-client
+ jar
+ JBoss jnp client jar
+
+
+
+ org.jboss.naming
+ jnpserver
+
+
+ org.jboss.logging
+ jboss-logging
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ org.jboss.naming:jnpserver
+ org.jboss.logging:jboss-logging
+
+
+
+
+ org.jboss.naming:jnpserver
+
+ org/jnp/interfaces/**/*.class
+ org/jboss/naming/**/*.class
+ org/jnp/server/NamingServer_Stub.class
+
+
+
+ org.jboss.logging:jboss-logging
+
+ org/jboss/logging/**/*.class
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/pom.xml b/distribution/pom.xml
new file mode 100644
index 0000000000..498d7611be
--- /dev/null
+++ b/distribution/pom.xml
@@ -0,0 +1,53 @@
+
+ 4.0.0
+
+
+ org.hornetq
+ hornetq-pom
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-distribution
+ pom
+ HornetQ Distribution
+
+
+ true
+ true
+
+
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+ org.jboss.naming
+ jnpserver
+
+
+ io.netty
+ netty-all
+
+
+
+
+ jnp-client
+ jboss-mc
+ hornetq
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
diff --git a/docs/README.html b/docs/README.html
new file mode 100644
index 0000000000..eca86ff683
--- /dev/null
+++ b/docs/README.html
@@ -0,0 +1,25 @@
+
+
+
+
+ HornetQ 2.4.1.Final Release Notes
+
+
+
+
Release Notes - HornetQ - Version 2.4.1 Final
+
+
+
+
22th January 2014
+
+These are the release notes for HornetQ 2.4.1.Final
+ Global Configuration Properties
+
+
+
+
+
+
+ Property Name
+ Property Type
+ Property Description
+
+
+
+
+ ConnectorClassName
+ String
+ The Connector class name (see for more information). If multiple connectors are
+ needed this should be provided as a comma separated list.
+
+
+ ConnectionParameters
+ String
+ The transport configuration. These parameters must be in the form of
+ key1=val1;key2=val2; and will be specific to the connector used. If
+ multiple connectors are configured then parameters should be supplied for each connector
+ separated by a comma.
+
+
+
+ ha
+ boolean
+ True if high availability is needed.
+
+
+ useLocalTx
+ boolean
+ True will enable local transaction optimisation.
+
+
+ UserName
+ String
+ The user name to use when making a connection
+
+
+ Password
+ String
+ The password to use when making a connection
+
+
+
+ DiscoveryAddress
+ String
+ The discovery group address to use to auto-detect a server
+
+
+
+ DiscoveryPort
+ Integer
+ The port to use for discovery
+
+
+
+ DiscoveryRefreshTimeout
+ Long
+ The timeout, in milliseconds, to refresh.
+
+
+
+
+ DiscoveryInitialWaitTimeout
+
+
+ Long
+ The initial time to wait for discovery.
+
+
+
+
+ ConnectionLoadBalancingPolicyClassName
+
+ String
+ The load balancing policy class to use.
+
+
+
+ ConnectionTTL
+
+ Long
+ The time to live (in milliseconds) for the connection.
+
+
+
+ CallTimeout
+
+ Long
+ the call timeout (in milliseconds) for each packet sent.
+
+
+
+ DupsOKBatchSize
+
+ Integer
+ the batch size (in bytes) between acknowledgements when using
+ DUPS_OK_ACKNOWLEDGE mode
+
+
+
+ TransactionBatchSize
+
+ Integer
+ the batch size (in bytes) between acknowledgements when using a
+ transactional session
+
+
+
+ ConsumerWindowSize
+
+ Integer
+ the window size (in bytes) for consumer flow control
+
+
+
+ ConsumerMaxRate
+
+ Integer
+ the fastest rate a consumer may consume messages per second
+
+
+
+ ConfirmationWindowSize
+
+ Integer
+ the window size (in bytes) for reattachment confirmations
+
+
+
+ ProducerMaxRate
+
+ Integer
+ the maximum rate of messages per second that can be sent
+
+
+
+ MinLargeMessageSize
+
+ Integer
+ the size (in bytes) before a message is treated as large
+
+
+
+ BlockOnAcknowledge
+
+ Boolean
+ whether or not messages are acknowledged synchronously
+
+
+
+ BlockOnNonDurableSend
+
+ Boolean
+ whether or not non-durable messages are sent synchronously
+
+
+
+ BlockOnDurableSend
+
+ Boolean
+ whether or not durable messages are sent synchronously
+
+
+
+ AutoGroup
+
+ Boolean
+ whether or not message grouping is automatically used
+
+
+
+ PreAcknowledge
+
+ Boolean
+ whether messages are pre acknowledged by the server before
+ sending
+
+
+
+ ReconnectAttempts
+
+ Integer
+ maximum number of retry attempts, default for the resource adapter is -1 (infinite attempts)
+
+
+
+ RetryInterval
+
+ Long
+ the time (in milliseconds) to retry a connection after failing
+
+
+
+ RetryIntervalMultiplier
+
+ Double
+ multiplier to apply to successive retry intervals
+
+
+
+ FailoverOnServerShutdown
+
+ Boolean
+ If true client will reconnect to another server if
+ available
+
+
+
+ ClientID
+
+ String
+ the pre-configured client ID for the connection factory
+
+
+
+ ClientFailureCheckPeriod
+
+ Long
+ the period (in ms) after which the client will consider the
+ connection failed after not receiving packets from the
+ server
+
+
+
+ UseGlobalPools
+
+ Boolean
+ whether or not to use a global thread pool for threads
+
+
+
+ ScheduledThreadPoolMaxSize
+
+ Integer
+ the size of the scheduled thread pool
+
+
+
+ ThreadPoolMaxSize
+
+ Integer
+ the size of the thread pool
+
+
+ SetupAttempts
+ Integer
+ Number of attempts to setup a JMS connection (default is 10, -1 means to attempt infinitely). It is possible
+ that the MDB is deployed before the JMS resources are available. In that case, the resource
+ adapter will try to setup several times until the resources are available. This applies only for inbound connections
+
+
+ SetupInterval
+ Long
+ Interval in milliseconds between consecutive attempts to setup a JMS connection (default is 2000m). This applies only for inbound connections
+
+
+
+
+
+
+ Adapter Outbound Configuration
+ The outbound configuration should remain unchanged as they define connection
+ factories that are used by Java EE components. These Connection Factories can be
+ defined inside a configuration file that matches the name *-ds.xml. You'll find a default jms-ds.xml
+ configuration under the hornetq directory in the JBoss AS
+ deployment. The connection factories defined in this file inherit their
+ properties from the main ra.xml configuration but can also be
+ overridden. The following example shows how to override them.
+
+ Please note that this configuration only applies when HornetQ resource adapter is installed in
+ JBoss Application Server. If you are using another JEE application
+ server please refer to your application servers documentation for how to do
+ this.
+
+
+<tx-connection-factory>
+ <jndi-name>RemoteJmsXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>jms-ra.rar</rar-name>
+ <connection-definition>org.hornetq.ra.HornetQRAConnectionFactory
+</connection-definition>
+<config-property name="SessionDefaultType" type="String">javax.jms.Topic</config-property>
+ <config-property name="ConnectorClassName" type="String">
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+ </config-property>
+ <config-property name="ConnectionParameters" type="String">
+ port=5445</config-property>
+ <max-pool-size>20</max-pool-size>
+</tx-connection-factory>
+
+ overriding connectors
+ If the connector class name is overridden the all parameters must also be supplied.
+
+ In this example the connection factory will be bound to JNDI with the name
+ RemoteJmsXA and can be looked up in the usual way using JNDI
+ or defined within the EJB or MDB as such:
+
+@Resource(mappedName="java:/RemoteJmsXA")
+private ConnectionFactory connectionFactory;
+ The config-property elements are what overrides those in the
+ ra.xml configuration file. Any of the elements pertaining to the
+ connection factory can be overridden here.
+ The outbound configuration also defines additional properties in addition to the global configuration properties.
+
+
+ Outbound Configuration Properties
+
+
+
+
+
+
+ Property Name
+ Property Type
+ Property Description
+
+
+
+
+ SessionDefaultType
+ String
+ the default session type
+
+
+ UseTryLock
+ Integer
+ try to obtain a lock within specified number of seconds. less
+ than or equal to 0 disable this functionality
+
+
+
+
+
+
+ Adapter Inbound Configuration
+ The inbound configuration should again remain unchanged. This controls what
+ forwards messages onto MDBs. It is possible to override properties on the MDB by
+ adding an activation configuration to the MDB itself. This could be used to
+ configure the MDB to consume from a different server.
+ The inbound configuration also defines additional properties in addition to the global configuration properties.
+
+
+ Inbound Configuration Properties
+
+
+
+
+
+
+ Property Name
+ Property Type
+ Property Description
+
+
+
+
+ Destination
+ String
+ JNDI name of the destination
+
+
+ DestinationType
+ String
+ type of the destination, either javax.jms.Queue or javax.jms.Topic
+ (default is javax.jms.Queue)
+
+
+ AcknowledgeMode
+ String
+ The Acknowledgment mode, either Auto-acknowledge or Dups-ok-acknowledge
+ (default is Auto-acknowledge). AUTO_ACKNOWLEDGE and DUPS_OK_ACKNOWLEDGE are acceptable values.
+
+
+ JndiParams
+ String
+ A semicolon (';') delimited string of name=value pairs which represent the properties to be used for the destination JNDI
+ look up. The properties depends on the JNDI implementation of the server hosting HornetQ. Typically only be used when the MDB is
+ configured to consume from a remote destination and needs to look up a JNDI reference rather than the HornetQ name of the
+ destination. Only relevant when useJNDI is true (default is an empty string).
+
+
+ MaxSession
+ Integer
+ Maximum number of session created by this inbound configuration (default is 15)
+
+
+ MessageSelector
+ String
+ the message selector of the consumer
+
+
+ SubscriptionDurability
+ String
+ Type of the subscription, either Durable or NonDurable
+
+
+ ShareSubscriptions
+ Boolean
+ When true, multiple MDBs can share the same Durable subscription
+
+
+ SubscriptionName
+ String
+ Name of the subscription
+
+
+ TransactionTimeout
+ Long
+ The transaction timeout in milliseconds (default is 0, the transaction does not timeout)
+
+
+ UseJNDI
+ Boolean
+ Whether or not use JNDI to look up the destination (default is true)
+
+
+
+
+
+
+
+ Configuring the adapter to use a standalone HornetQ Server
+ Sometime you may want your messaging server on a different machine or separate from the application server.
+ If this is the case you will only need the hornetq client libs installed. This section explains what config to create
+ and what jar dependencies are needed.
+
+ There are two configuration files needed to do this, one for the incoming adapter used for MDB's
+ and one for outgoing connections managed by the JCA managed connection pool used by outgoing JEE components
+ wanting outgoing connections.
+
+ Configuring the Incoming Adaptor
+ Firstly you will need to create directory under the
+ deploy
+ directory ending in
+ .rar.
+ For this example we will name the directory hornetq-ra.rar. This detail is
+ important as
+ the name of directory is referred to by the MDB's and the outgoing configuration.
+
+
+
+ The jboss default for this is jms-ra.rar, If you don't want to have to
+ configure your
+ MDB's you can use this but you may need to remove the generic adaptor that uses this.
+
+
+ Under the
+ hornetq-ra.rar
+ directory you will need to create a
+ META-INF
+ directory into which you should create an
+ ra.xml
+ configuration file. You can find a template
+ for the
+ ra.xml
+ under the config directory of the HornetQ distribution.
+
+ To configure MDB's to consume messages from a remote HornetQ server you need to edit the
+ ra.xml
+ file under
+ deploy/hornet-ra.rar/META-INF
+ and change the transport type to
+ use a netty connector (instead of the invm connector that is defined) and configure its transport
+ parameters.
+ Heres an example of what this would look like:
+
+
+<resourceadapter-class>org.hornetq.ra.HornetQResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>The transport type</description>
+ <config-property-name>ConnectorClassName</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</config-property-value>
+ </config-property>
+ <config-property>
+ <description>The transport configuration. These values must be in the form of key=val;key=val;</description>
+ <config-property-name>ConnectionParameters</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>host=127.0.0.1;port=5446</config-property-value>
+</config-property>
+
+ If you want to provide a list of servers that the adapter can connect to you can provide a list of
+ connectors, each separated by a comma.
+
+
+
+<resourceadapter-class>org.hornetq.ra.HornetQResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>The transport type</description>
+ <config-property-name>ConnectorClassName</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory,org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</config-property-value>
+ </config-property>
+ <config-property>
+ <description>The transport configuration. These values must be in the form of key=val;key=val;</description>
+ <config-property-name>ConnectionParameters</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>host=127.0.0.1;port=5446,host=127.0.0.2;port=5447</config-property-value>
+</config-property>
+
+ provide all parameters
+
+ Make sure you provide parameters for each connector configured. The position of the parameters in the
+ list maps to each connector provided.
+
+
+ This configures the resource adapter to connect to a server running on localhost listening on port
+ 5446
+
+
+
+
+ Configuring the outgoing adaptor
+ You will also need to configure the outbound connection by creating a hornetq-ds.xml
+ and placing it under any directory that will be deployed under the deploy directory.
+ In a standard HornetQ jboss configuration this would be under hornetq or hornetq.sar
+ but you can place it where ever you like. Actually as long as it ends in -ds.xml you can
+ call it anything you like. You can again find a template for this file under the config directory of the
+ HornetQ distribution but called jms-ds.xml which is the jboss default.
+
+ The following example shows a sample configuration
+
+<tx-connection-factory>
+ <jndi-name>RemoteJmsXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>hornetq-ra.rar</rar-name>
+ <connection-definition>org.hornetq.ra.HornetQRAConnectionFactory</connection-definition>
+ <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
+ <config-property name="ConnectorClassName" type="java.lang.String">org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</config-property>
+ <config-property name="ConnectionParameters" type="java.lang.String">host=127.0.0.1;port=5446</config-property>
+ <max-pool-size>20</max-pool-size>
+</tx-connection-factory>
+ Again you will see that this uses the netty connector type and will connect to the HornetQ server
+ running on localhost and listening on port 5446. JEE components can access this by using JNDI and looking
+ up the connection factory using JNDI using java:/RemoteJmsXA, you can see that this
+ is defined under thejndi-name attribute. You will also note that the outgoing connection
+ will be created by the resource adaptor configured under the directory hornetq-ra.rar
+ as explained in the last section.
+
+
+ Also if you want to configure multiple connectors do this as a comma separated list as in the ra configuration.
+
+
+
+
+ Jar dependencies
+ This is a list of the HornetQ and third party jars needed
+
+ Jar Dependencies
+
+
+
+
+
+
+ Jar Name
+ Description
+ Location
+
+
+
+
+ hornetq-ra.jar
+ The HornetQ resource adaptor classes
+ deploy/hornetq-ra.rar or equivalent
+
+
+ hornetq-core-client.jar
+ The HornetQ core client classes
+ either in the config lib, i.e. default/lib or the common lib dir, i.e. $JBOSS_HOME/common lib
+
+
+ hornetq-jms-client.jar
+ The HornetQ JMS classes
+ as above
+
+
+ netty.jar
+ The Netty transport classes
+ as above
+
+
+
+
+
+
+
+
+
+
+ Configuring the JBoss Application Server to connect to Remote HornetQ Server
+ This is a step by step guide on how to configure a JBoss application server that doesn't have HornetQ installed
+ to use a remote instance of HornetQ
+
+ Configuring JBoss 5
+ Firstly download and install JBoss AS 5 as per the JBoss installation guide and HornetQ as per the
+ HornetQ installation guide. After that the following steps are required
+
+
+ Copy the following jars from the HornetQ distribution to the lib directory of
+ which ever JBossAs configuration you have chosen, i.e. default.
+
+
+ hornetq-core-client.jar
+
+
+ hornetq-jms-client.jar
+
+
+ hornetq-ra.jar (this can be found inside the hornetq-ra.rar archive)
+
+
+ netty.jar
+
+
+
+
+ create the directories hornetq-ra.rar and hornetq-ra.rar/META-INF
+ under the deploy directory in your JBoss config directory
+
+
+ under the hornetq-ra.rar/META-INF create a ra.xml file or
+ copy it from the HornetQ distribution (again it can be found in the hornetq-ra.rar archive)
+ and configure it as follows
+
+<?xml version="1.0" encoding="UTF-8"?>
+
+<connector xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+ http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
+ version="1.5">
+
+ <description>HornetQ 2.0 Resource Adapter Alternate Configuration</description>
+ <display-name>HornetQ 2.0 Resource Adapter Alternate Configuration</display-name>
+
+ <vendor-name>Red Hat Middleware LLC</vendor-name>
+ <eis-type>JMS 1.1 Server</eis-type>
+ <resourceadapter-version>1.0</resourceadapter-version>
+
+ <license>
+ <description>
+Copyright 2009 Red Hat, Inc.
+ Red Hat 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.
+ </description>
+ <license-required>true</license-required>
+ </license>
+
+ <resourceadapter>
+ <resourceadapter-class>org.hornetq.ra.HornetQResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>The transport type</description>
+ <config-property-name>ConnectorClassName</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</config-property-value>
+ </config-property>
+ <config-property>
+ <description>The transport configuration. These values must be in the form of key=val;key=val;</description>
+ <config-property-name>ConnectionParameters</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>host=127.0.0.1;port=5445</config-property-value>
+ </config-property>
+
+ <outbound-resourceadapter>
+ <connection-definition>
+ <managedconnectionfactory-class>org.hornetq.ra.HornetQRAManagedConnectionFactory</managedconnectionfactory-class>
+
+ <config-property>
+ <description>The default session type</description>
+ <config-property-name>SessionDefaultType</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>javax.jms.Queue</config-property-value>
+ </config-property>
+ <config-property>
+ <description>Try to obtain a lock within specified number of seconds; less than or equal to 0 disable this functionality</description>
+ <config-property-name>UseTryLock</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>0</config-property-value>
+ </config-property>
+
+ <connectionfactory-interface>org.hornetq.ra.HornetQRAConnectionFactory</connectionfactory-interface>
+ <connectionfactory-impl-class>org.hornetq.ra.HornetQRAConnectionFactoryImpl</connectionfactory-impl-class>
+ <connection-interface>javax.jms.Session</connection-interface>
+ <connection-impl-class>org.hornetq.ra.HornetQRASession</connection-impl-class>
+ </connection-definition>
+ <transaction-support>XATransaction</transaction-support>
+ <authentication-mechanism>
+ <authentication-mechanism-type>BasicPassword</authentication-mechanism-type>
+ <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface>
+ </authentication-mechanism>
+ <reauthentication-support>false</reauthentication-support>
+ </outbound-resourceadapter>
+
+ <inbound-resourceadapter>
+ <messageadapter>
+ <messagelistener>
+ <messagelistener-type>javax.jms.MessageListener</messagelistener-type>
+ <activationspec>
+ <activationspec-class>org.hornetq.ra.inflow.HornetQActivationSpec</activationspec-class>
+ <required-config-property>
+ <config-property-name>destination</config-property-name>
+ </required-config-property>
+ </activationspec>
+ </messagelistener>
+ </messageadapter>
+ </inbound-resourceadapter>
+
+ </resourceadapter>
+</connector>
+ The important part of this configuration is the part in bold, i.e. <config-property-value>host=127.0.0.1;port=5445</config-property-value>.
+ This should be configured to the host and port of the remote HornetQ server.
+
+
+ At this point you should be able to now deploy MDB's that consume from the remote server. You will however,
+ have to make sure that your MDB's have the annotation @ResourceAdapter("hornetq-ra.rar")
+ added, this is illustrated in the Configuring Message-Driven Beans section.
+ If you don't want to add this annotation then you can delete the generic resource adapter jms-ra.rar
+ and rename the hornetq-ra.rar to this.
+ If you also want to use the remote HornetQ server for outgoing connections, i.e. sending messages, then
+ do the following:
+
+
+ Create a file called hornetq-ds.xml in the deploy directory
+ (in fact you can call this anything you want as long as it ends in -ds.xml). Then
+ add the following:
+
+<connection-factories>
+ <!--
+ JMS XA Resource adapter, use this for outbound JMS connections.
+ Inbound connections are defined at the @MDB activation or at the resource-adapter properties.
+ -->
+ <tx-connection-factory>
+ <jndi-name>RemoteJmsXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>hornetq-ra.rar</rar-name>
+ <connection-definition>org.hornetq.ra.HornetQRAConnectionFactory</connection-definition>
+ <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
+ <config-property name="ConnectorClassName" type="java.lang.String">org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</config-property>
+ <config-property name="ConnectionParameters" type="java.lang.String">host=127.0.0.1;port=5445</config-property>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+
+</connection-factories>
+ Again you will see that the host and port are configured here to match the remote HornetQ servers
+ configuration. The other important attributes are:
+
+
+ jndi-name - This is the name used to look up the JMS connection factory from within your JEE client
+
+
+ rar-name - This should match the directory that you created to hold the Resource Adapter
+ configuration
+
+
+
+
+ Now you should be able to send messages using the JCA JMS connection pooling within an XA transaction.
+
+
+ Configuring JBoss 5
+ The steps to do this are exactly the same as for JBoss 4, you will have to create a jboss.xml definition
+ file for your MDB with the following entry
+
+<message-driven>
+ <ejb-name>MyMDB</ejb-name>
+ <resource-adapter-name>jms-ra.rar</resource-adapter-name>
+ </message-driven>
+ Also you will need to edit the standardjboss.xml and uncomment the section with the
+ following 'Uncomment to use JMS message inflow from jmsra.rar' and then comment out the invoker-proxy-binding
+ called 'message-driven-bean'
+
+
+
+ High Availability JNDI (HA-JNDI)
+ If you are using JNDI to look-up JMS queues, topics and connection factories from a
+ cluster of servers, it is likely you will want to use HA-JNDI so that your JNDI look-ups
+ will continue to work if one or more of the servers in the cluster fail.
+ HA-JNDI is a JBoss Application Server service which allows you to use JNDI from
+ clients without them having to know the exact JNDI connection details of every server in
+ the cluster. This service is only available if using a cluster of JBoss Application
+ Server instances.
+ To use it use the following properties when connecting to JNDI.
+
+Hashtable<String, String> jndiParameters = new Hashtable<String, String>();
+jndiParameters.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
+jndiParameters.put("java.naming.factory.url.pkgs=", "org.jboss.naming:org.jnp.interfaces");
+
+initialContext = new InitialContext(jndiParameters);
+ For more information on using HA-JNDI see the JBoss Application Server clustering documentation
+
+
+ XA Recovery
+ XA recovery deals with system or application failures to ensure
+ that of a transaction are applied consistently to all resources affected by the
+ transaction, even if any of the application processes or the machine hosting them crash
+ or lose network connectivity. For more information on XA Recovery,please refer to JBoss
+ Transactions.
+ When HornetQ is integrated with JBoss AS, it can take advantage of JBoss Transactions
+ to provide recovery of messaging resources. If messages are involved in a XA
+ transaction, in the event of a server crash, the recovery manager will ensure that the
+ transactions are recovered and the messages will either be committed or rolled back
+ (depending on the transaction outcome) when the server is restarted.
+
+ XA Recovery Configuration
+ To enable HornetQ's XA Recovery, the Recovery Manager must be configured to connect
+ to HornetQ to recover its resources. The following property must be added to the
+ jta section of conf/jbossts-properties.xml
+ of JBoss AS profiles:
+
+<properties depends="arjuna" name="jta">
+ ...
+
+ <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.HornetQ1"
+ value="org.hornetq.jms.server.recovery.HornetQXAResourceRecovery;[connection configuration]"/>
+ <property name="com.arjuna.ats.jta.xaRecoveryNode" value="1"/>
+</properties>
+ The [connection configuration] contains all the information
+ required to connect to HornetQ node under the form [connector factory class
+ name],[user name], [password], [connector parameters].
+
+
+ [connector factory class name] corresponds to the name
+ of the ConnectorFactory used to connect to HornetQ.
+ Values can be org.hornetq.core.remoting.impl.invm.InVMConnectorFactory or
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+ [user name] is the user name to create a client
+ session. It is optional
+
+
+ [password] is the password to create a client session.
+ It is mandatory only if the user name is specified
+
+
+ [connector parameters] is a list of comma-separated
+ key=value pair which are passed to the connector factory (see for a list of the transport
+ parameters).
+
+
+ Also note the com.arjuna.ats.jta.xaRecoveryNode parameter. If you want recovery
+ enabled then this must be configured to what ever the tx node id is set to, this is configured in the
+ same file by the com.arjuna.ats.arjuna.xa.nodeIdentifier property.
+
+ HornetQ must have a valid acceptor which corresponds to the connector
+ specified in conf/jbossts-properties.xml.
+
+
+ Configuration Settings
+ If HornetQ is configured with a default in-vm acceptor:
+
+<acceptor name="in-vm">
+ <factory-class>org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory</factory-class>
+</acceptor>
+ the corresponding configuration in conf/jbossts-properties.xml is:
+
+<property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.HORNETQ1"
+ value="org.hornetq.jms.server.recovery.HornetQXAResourceRecovery;org.hornetq.core.remoting.impl.invm.InVMConnectorFactory"/>
+ If it is now configured with a netty acceptor on a non-default port:
+
+<acceptor name="netty">
+ <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
+ <param key="port" value="8888"/>
+</acceptor>
+ the corresponding configuration in conf/jbossts-properties.xml is:
+
+<property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.HORNETQ1"
+ value="org.hornetq.jms.server.recovery.HornetQXAResourceRecovery;org.hornetq.core.remoting.impl.netty.NettyConnectorFactory, , , port=8888"/>
+
+ Note the additional commas to skip the user and password before connector
+ parameters
+
+ If the recovery must use admin, adminpass, the
+ configuration would have been:
+
+<property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.HORNETQ1"
+ value="org.hornetq.jms.server.recovery.HornetQXAResourceRecovery;org.hornetq.core.remoting.impl.netty.NettyConnectorFactory, admin, adminpass, port=8888"/>
+ Configuring HornetQ with an invm acceptor and configuring the Recovery Manager
+ with an invm connector is the recommended way to enable XA Recovery.
+
+
+
+ Example
+ See which shows how to configure XA Recovery
+ and recover messages after a server crash.
+
+
+
diff --git a/docs/user-manual/en/architecture.xml b/docs/user-manual/en/architecture.xml
new file mode 100644
index 0000000000..8b7085cba7
--- /dev/null
+++ b/docs/user-manual/en/architecture.xml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Architecture
+ In this section we will give an overview of the HornetQ high level architecture.
+
+ Core Architecture
+ HornetQ core is designed simply as set of Plain Old Java Objects (POJOs) - we hope you
+ like its clean-cut design.
+ We've also designed it to have as few dependencies on external jars as possible. In
+ fact, HornetQ core has only one jar dependency, netty.jar,
+ other than the standard JDK classes! This is because we use some of the netty buffer classes
+ internally.
+ This allows HornetQ to be easily embedded in your own project, or instantiated in any
+ dependency injection framework such as JBoss Microcontainer, Spring or Google
+ Guice.
+ Each HornetQ server has its own ultra high performance persistent journal, which it
+ uses for message and other persistence.
+ Using a high performance journal allows outrageous persistence message performance,
+ something not achievable when using a relational database for persistence.
+ HornetQ clients, potentially on different physical machines interact with the HornetQ
+ server. HornetQ currently provides two APIs for messaging at the client side:
+
+
+
+ Core client API. This is a simple intuitive Java API that allows the full
+ set of messaging functionality without some of the complexities of
+ JMS.
+
+
+ JMS client API. The standard JMS API is available at the client
+ side.
+
+
+
+ JMS semantics are implemented by a thin JMS facade layer on the client side.
+ The HornetQ server does not speak JMS and in fact does not know anything about JMS,
+ it is a protocol agnostic messaging server designed to be used with multiple different
+ protocols.
+ When a user uses the JMS API on the client side, all JMS interactions are translated
+ into operations on the HornetQ core client API before being transferred over the wire
+ using the HornetQ wire format.
+ The server always just deals with core API interactions.
+ A schematic illustrating this relationship is shown in figure 3.1 below:
+
+
+
+ Figure 3.1 shows two user applications interacting with a HornetQ server. User
+ Application 1 is using the JMS API, while User Application 2 is using the core client
+ API directly.
+ You can see from the diagram that the JMS API is implemented by a thin facade layer on
+ the client side.
+
+
+ HornetQ embedded in your own application
+ HornetQ core is designed as a set of simple POJOs so if you have an application that
+ requires messaging functionality internally but you don't want to expose that as a
+ HornetQ server you can directly instantiate and embed HornetQ servers in your own
+ application.
+ For more information on embedding HornetQ, see .
+
+
+ HornetQ integrated with a JEE application server
+ HornetQ provides its own fully functional Java Connector Architecture (JCA) adaptor
+ which enables it to be integrated easily into any JEE compliant application server or
+ servlet engine.
+ JEE application servers provide Message Driven Beans (MDBs), which are a special type
+ of Enterprise Java Beans (EJBs) that can process messages from sources such as JMS
+ systems or mail systems.
+ Probably the most common use of an MDB is to consume messages from a JMS messaging
+ system.
+ According to the JEE specification, a JEE application server uses a JCA adapter to
+ integrate with a JMS messaging system so it can consume messages for MDBs.
+ However, the JCA adapter is not only used by the JEE application server for consuming messages via MDBs, it is also used when sending
+ message to the JMS messaging system e.g. from inside an EJB or servlet.
+ When integrating with a JMS messaging system from inside a JEE application server it
+ is always recommended that this is done via a JCA adaptor. In fact, communicating with a
+ JMS messaging system directly, without using JCA would be illegal according to the JEE
+ specification.
+ The application server's JCA service provides extra functionality such as connection
+ pooling and automatic transaction enlistment, which are desirable when using messaging,
+ say, from inside an EJB. It is possible to talk to a JMS messaging system directly from
+ an EJB, MDB or servlet without going through a JCA adapter, but this is not recommended
+ since you will not be able to take advantage of the JCA features, such as caching of JMS
+ sessions, which can result in poor performance.
+ Figure 3.2 below shows a JEE application server integrating with a HornetQ server via
+ the HornetQ JCA adaptor. Note that all communication between EJB sessions or entity
+ beans and Message Driven beans go through the adaptor and not directly to
+ HornetQ.
+ The large arrow with the prohibited sign shows an EJB session bean talking directly to
+ the HornetQ server. This is not recommended as you'll most likely end up creating a new
+ connection and session every time you want to interact from the EJB, which is an
+ anti-pattern.
+
+
+
+ For more information on using the JCA adaptor, please see .
+
+
+ HornetQ stand-alone server
+ HornetQ can also be deployed as a stand-alone server. This means a fully independent
+ messaging server not dependent on a JEE application server.
+ The standard stand-alone messaging server configuration comprises a core messaging
+ server, a JMS service and a JNDI service.
+ The role of the JMS Service is to deploy any JMS Queue, Topic and ConnectionFactory
+ instances from any server side hornetq-jms.xml configuration files.
+ It also provides a simple management API for creating and destroying Queues, Topics and
+ ConnectionFactory instances which can be accessed via JMX or the connection. It is a
+ separate service to the HornetQ core server, since the core server is JMS agnostic. If
+ you don't want to deploy any JMS Queue, Topic or ConnectionFactory instances via server
+ side XML configuration and don't require a JMS management API on the server side then
+ you can disable this service.
+ We also include a JNDI server since JNDI is a common requirement when using JMS to
+ lookup Queues, Topics and ConnectionFactory instances. If you do not require JNDI then
+ this service can also be disabled. HornetQ allows you to programmatically create JMS and
+ core objects directly on the client side as opposed to looking them up from JNDI, so a
+ JNDI server is not always a requirement.
+ The stand-alone server configuration uses JBoss Microcontainer to instantiate and
+ enforce dependencies between the components. JBoss Microcontainer is a very lightweight
+ POJO bootstrapper.
+ The stand-alone server architecture is shown in figure 3.3 below:
+
+
+
+ For more information on server configuration files see . $
+
+
diff --git a/docs/user-manual/en/client-classpath.xml b/docs/user-manual/en/client-classpath.xml
new file mode 100644
index 0000000000..be94909c57
--- /dev/null
+++ b/docs/user-manual/en/client-classpath.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ The Client Classpath
+ HornetQ requires several jars on the Client Classpath depending on
+ whether the client uses HornetQ Core API, JMS, and JNDI.
+
+ All the jars mentioned here can be found in the lib directory of
+ the HornetQ distribution. Be sure you only use the jars from the correct version of the
+ release, you must not mix and match versions of jars from different
+ HornetQ versions. Mixing and matching different jar versions may cause subtle errors and
+ failures to occur.
+
+
+ HornetQ Core Client
+ If you are using just a pure HornetQ Core client (i.e. no JMS) then you need hornetq-core-client.jar, hornetq-commons.jar, and
+ netty.jar on your client classpath.
+
+
+ JMS Client
+ If you are using JMS on the client side, then you will also need to include hornetq-jms-client.jar and jboss-jms-api.jar.
+
+
+ jboss-jms-api.jar just contains Java EE API interface classes
+ needed for the javax.jms.* classes. If you already have a jar
+ with these interface classes on your classpath, you will not need it.
+
+
+
+
+ JMS Client with JNDI
+ If you are looking up JMS resources from the JNDI server co-located with the HornetQ
+ standalone server, you will also need the jar jnp-client.jar jar on
+ your client classpath as well as any other jars mentioned previously.
+
+
diff --git a/docs/user-manual/en/client-reconnection.xml b/docs/user-manual/en/client-reconnection.xml
new file mode 100644
index 0000000000..d647011672
--- /dev/null
+++ b/docs/user-manual/en/client-reconnection.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Client Reconnection and Session Reattachment
+ HornetQ clients can be configured to automatically reconnect or re-attach to the server in
+ the event that a failure is detected in the connection between the client and the server.
+
+ 100% Transparent session re-attachment
+ If the failure was due to some transient failure such as a temporary network failure,
+ and the target server was not restarted, then the sessions will still be existent on the
+ server, assuming the client hasn't been disconnected for more than connection-ttl .
+ In this scenario, HornetQ will automatically re-attach the client sessions to the
+ server sessions when the connection reconnects. This is done 100% transparently and the
+ client can continue exactly as if nothing had happened.
+ The way this works is as follows:
+ As HornetQ clients send commands to their servers they store each sent command in an
+ in-memory buffer. In the case that connection failure occurs and the client subsequently
+ reattaches to the same server, as part of the reattachment protocol the server informs
+ the client during reattachment with the id of the last command it successfully received
+ from that client.
+ If the client has sent more commands than were received before failover it can replay
+ any sent commands from its buffer so that the client and server can reconcile their
+ states.
+ The size of this buffer is configured by the ConfirmationWindowSize
+ parameter, when the server has received ConfirmationWindowSize bytes
+ of commands and processed them it will send back a command confirmation to the client,
+ and the client can then free up space in the buffer.
+ If you are using JMS and you're using the JMS service on the server to load your JMS
+ connection factory instances into JNDI then this parameter can be configured in hornetq-jms.xml using the element confirmation-window-size a. If you're using JMS but not using JNDI then
+ you can set these values directly on the HornetQConnectionFactory
+ instance using the appropriate setter method.
+ If you're using the core API you can set these values directly on the ServerLocator instance using the appropriate setter method.
+ The window is specified in bytes.
+ Setting this parameter to -1 disables any buffering and prevents
+ any re-attachment from occurring, forcing reconnect instead. The default value for this
+ parameter is -1. (Which means by default no auto re-attachment will occur)
+
+
+ Session reconnection
+ Alternatively, the server might have actually been restarted after crashing or being
+ stopped. In this case any sessions will no longer be existent on the server and it won't
+ be possible to 100% transparently re-attach to them.
+ In this case, HornetQ will automatically reconnect the connection and recreate any sessions and consumers on the server
+ corresponding to the sessions and consumers on the client. This process is exactly the
+ same as what happens during failover onto a backup server.
+ Client reconnection is also used internally by components such as core bridges to
+ allow them to reconnect to their target servers.
+ Please see the section on failover to get a
+ full understanding of how transacted and non-transacted sessions are reconnected during
+ failover/reconnect and what you need to do to maintain once and
+ only once delivery guarantees.
+
+
+ Configuring reconnection/reattachment attributes
+ Client reconnection is configured using the following parameters:
+
+
+ retry-interval. 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 2000 milliseconds.
+
+
+ retry-interval-multiplier. This optional parameter
+ determines determines a multiplier to apply to the time since the last retry to
+ compute the time to the next retry.
+ This allows you to implement an exponential backoff
+ between retry attempts.
+ Let's take an example:
+ If we set retry-interval to 1000 ms and
+ we set retry-interval-multiplier to 2.0,
+ then, if the first reconnect attempt fails, we will wait 1000
+ ms then 2000 ms then 4000 ms between
+ subsequent reconnection attempts.
+ The default value is 1.0 meaning each reconnect attempt is
+ spaced at equal intervals.
+
+
+ max-retry-interval. This optional parameter determines the
+ maximum retry interval that will be used. When setting retry-interval-multiplier it would otherwise be possible that
+ subsequent retries exponentially increase to ridiculously large values. By
+ setting this parameter you can set an upper limit on that value. The default
+ value is 2000 milliseconds.
+
+
+ reconnect-attempts. This optional parameter determines the
+ total number of reconnect attempts to make before giving up and shutting down. A
+ value of -1 signifies an unlimited number of attempts. The
+ default value is 0.
+
+
+ If you're using JMS, and you're using the JMS Service on the server to load your JMS
+ connection factory instances directly into JNDI, then you can specify these parameters
+ in the xml configuration in hornetq-jms.xml, for example:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ <entry name="XAConnectionFactory"/>
+ </entries>
+ <retry-interval>1000</retry-interval>
+ <retry-interval-multiplier>1.5</retry-interval-multiplier>
+ <max-retry-interval>60000</max-retry-interval>
+ <reconnect-attempts>1000</reconnect-attempts>
+</connection-factory>
+ If you're using JMS, but instantiating your JMS connection factory directly, you can
+ specify the parameters using the appropriate setter methods on the HornetQConnectionFactory immediately after creating it.
+ If you're using the core API and instantiating the ServerLocator instance directly you can also specify the
+ parameters using the appropriate setter methods on the ServerLocator immediately after creating it.
+ If your client does manage to reconnect but the session is no longer available on the
+ server, for instance if the server has been restarted or it has timed out, then the
+ client won't be able to re-attach, and any ExceptionListener or
+ FailureListener instances registered on the connection or session
+ will be called.
+
+
+ ExceptionListeners and SessionFailureListeners
+ Please note, that when a client reconnects or re-attaches, any registered JMS ExceptionListener or core API SessionFailureListener
+ will be called.
+
+
diff --git a/docs/user-manual/en/clusters.xml b/docs/user-manual/en/clusters.xml
new file mode 100644
index 0000000000..25e79b211f
--- /dev/null
+++ b/docs/user-manual/en/clusters.xml
@@ -0,0 +1,998 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %BOOK_ENTITIES;
+ ]>
+
+ Clusters
+
+ Clusters Overview
+ HornetQ clusters allow groups of HornetQ servers to be grouped together in order to
+ share message processing load. Each active node in the cluster is an active HornetQ
+ server which manages its own messages and handles its own connections.
+
+ The clustered parameter is deprecated and no longer needed for
+ setting up a cluster. If your configuration contains this parameter it will be ignored and
+ a message with the ID HQ221038 will be logged.
+
+ The cluster is formed by each node declaring cluster connections
+ to other nodes in the core configuration file hornetq-configuration.xml. When a node forms a cluster connection to
+ another node, internally it creates a core bridge (as described in
+ ) connection between it and the other node, this is
+ done transparently behind the scenes - you don't have to declare an explicit bridge for
+ each node. These cluster connections allow messages to flow between the nodes of the
+ cluster to balance load.
+ Nodes can be connected together to form a cluster in many different topologies, we
+ will discuss a couple of the more common topologies later in this chapter.
+ We'll also discuss client side load balancing, where we can balance client connections
+ across the nodes of the cluster, and we'll consider message redistribution where HornetQ
+ will redistribute messages between nodes to avoid starvation.
+ Another important part of clustering is server discovery where
+ servers can broadcast their connection details so clients or other servers can connect
+ to them with the minimum of configuration.
+
+ Once a cluster node has been configured it is common to simply copy that configuration
+ to other nodes to produce a symmetric cluster. However, care must be taken when copying the
+ HornetQ files. Do not copy the HornetQ data (i.e. the
+ bindings, journal, and large-messages
+ directories) from one node to another. When a node is started for the first time and initializes
+ its journal files it also persists a special identifier to the journal
+ directory. This id must be unique among nodes in the cluster or the
+ cluster will not form properly.
+
+
+
+ Server discovery
+ Server discovery is a mechanism by which servers can propagate their connection details to:
+
+
+
+ Messaging clients. A messaging client wants to be able to connect
+ to the servers of the cluster without having specific knowledge of which servers
+ in the cluster are up at any one time.
+
+
+
+ Other servers. Servers in a cluster want to be able to create
+ cluster connections to each other without having prior knowledge of all the
+ other servers in the cluster.
+
+
+
+ This information, let's call it the Cluster Topology, is actually sent around normal HornetQ
+ connections to clients and to other servers over cluster connections. This being the case we need a
+ way of establishing the initial first connection. This can be done using
+ dynamic discovery techniques like UDP
+ and JGroups, or by
+ providing a list of initial connectors.
+
+
+ Dynamic Discovery
+
+ Server discovery uses UDP
+ multicast or JGroups to broadcast server connection settings.
+
+
+ Broadcast Groups
+ A broadcast group is the means by which a server broadcasts connectors over the
+ network. A connector defines a way in which a client (or other server) can make
+ connections to the server. For more information on what a connector is, please see
+ .
+ The broadcast group takes a set of connector pairs, each connector pair contains
+ connection settings for a live and backup server (if one exists) and broadcasts them on
+ the network. Depending on which broadcasting technique you configure the cluster, it
+ uses either UDP or JGroups to broadcast connector pairs information.
+ Broadcast groups are defined in the server configuration file hornetq-configuration.xml. There can be many broadcast groups per
+ HornetQ server. All broadcast groups must be defined in a broadcast-groups element.
+ Let's take a look at an example broadcast group from hornetq-configuration.xml that defines a UDP broadcast group:
+
+<broadcast-groups>
+ <broadcast-group name="my-broadcast-group">
+ <local-bind-address>172.16.9.3</local-bind-address>
+ <local-bind-port>5432</local-bind-port>
+ <group-address>231.7.7.7</group-address>
+ <group-port>9876</group-port>
+ <broadcast-period>2000</broadcast-period>
+ <connector-ref connector-name="netty-connector"/>
+ </broadcast-group>
+</broadcast-groups>
+ Some of the broadcast group parameters are optional and you'll normally use the
+ defaults, but we specify them all in the above example for clarity. Let's discuss
+ each one in turn:
+
+
+ name attribute. Each broadcast group in the server must
+ have a unique name.
+
+
+ local-bind-address. This is the local bind address that
+ the datagram socket is bound to. If you have multiple network interfaces on
+ your server, you would specify which one you wish to use for broadcasts by
+ setting this property. If this property is not specified then the socket
+ will be bound to the wildcard address, an IP address chosen by the
+ kernel. This is a UDP specific attribute.
+
+
+ local-bind-port. If you want to specify a local port to
+ which the datagram socket is bound you can specify it here. Normally you
+ would just use the default value of -1 which signifies
+ that an anonymous port should be used. This parameter is always specified in conjunction with
+ local-bind-address. This is a UDP specific attribute.
+
+
+ group-address. This is the multicast address to which
+ the data will be broadcast. It is a class D IP address in the range 224.0.0.0 to 239.255.255.255, inclusive.
+ The address 224.0.0.0 is reserved and is not available
+ for use. This parameter is mandatory. This is a UDP specific attribute.
+
+
+ group-port. This is the UDP port number used for
+ broadcasting. This parameter is mandatory. This is a UDP specific attribute.
+
+
+ broadcast-period. This is the period in milliseconds
+ between consecutive broadcasts. This parameter is optional, the default
+ value is 2000 milliseconds.
+
+
+ connector-ref. This specifies the connector and
+ optional backup connector that will be broadcasted (see for more information on connectors).
+ The connector to be broadcasted is specified by the connector-name attribute.
+
+
+
+ Here is another example broadcast group that defines a JGroups broadcast group:
+
+<broadcast-groups>
+ <broadcast-group name="my-broadcast-group">
+ <jgroups-file>test-jgroups-file_ping.xml</jgroups-file>
+ <jgroups-channel>hornetq_broadcast_channel</jgroups-channel>
+ <broadcast-period>2000</broadcast-period>
+ <connector-ref connector-name="netty-connector"/>
+ </broadcast-group>
+</broadcast-groups>
+ To be able to use JGroups to broadcast, one must specify two attributes, i.e.
+ jgroups-file and jgroups-channel, as discussed
+ in details as following:
+
+
+ jgroups-file attribute. This is the name of JGroups configuration
+ file. It will be used to initialize JGroups channels. Make sure the file is in the
+ java resource path so that HornetQ can load it.
+
+
+ jgroups-channel attribute. The name that JGroups channels connect
+ to for broadcasting.
+
+
+
+ The JGroups attributes (jgroups-file and jgroups-channel)
+ and UDP specific attributes described above are exclusive of each other. Only one set can be
+ specified in a broadcast group configuration. Don't mix them!
+
+
+ The following is an example of a JGroups file
+
+<config xmlns="urn:org:jgroups"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.0.xsd">
+ <TCP loopback="true"
+ recv_buf_size="20000000"
+ send_buf_size="640000"
+ discard_incompatible_packets="true"
+ max_bundle_size="64000"
+ max_bundle_timeout="30"
+ enable_bundling="true"
+ use_send_queues="false"
+ sock_conn_timeout="300"
+
+ thread_pool.enabled="true"
+ thread_pool.min_threads="1"
+ thread_pool.max_threads="10"
+ thread_pool.keep_alive_time="5000"
+ thread_pool.queue_enabled="false"
+ thread_pool.queue_max_size="100"
+ thread_pool.rejection_policy="run"
+
+ oob_thread_pool.enabled="true"
+ oob_thread_pool.min_threads="1"
+ oob_thread_pool.max_threads="8"
+ oob_thread_pool.keep_alive_time="5000"
+ oob_thread_pool.queue_enabled="false"
+ oob_thread_pool.queue_max_size="100"
+ oob_thread_pool.rejection_policy="run"/>
+
+ <FILE_PING location="../file.ping.dir"/>
+ <MERGE2 max_interval="30000"
+ min_interval="10000"/>
+ <FD_SOCK/>
+ <FD timeout="10000" max_tries="5" />
+ <VERIFY_SUSPECT timeout="1500" />
+ <BARRIER />
+ <pbcast.NAKACK
+ use_mcast_xmit="false"
+ retransmit_timeout="300,600,1200,2400,4800"
+ discard_delivered_msgs="true"/>
+ <UNICAST timeout="300,600,1200" />
+ <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+ max_bytes="400000"/>
+ <pbcast.GMS print_local_addr="true" join_timeout="3000"
+ view_bundling="true"/>
+ <FC max_credits="2000000"
+ min_threshold="0.10"/>
+ <FRAG2 frag_size="60000" />
+ <pbcast.STATE_TRANSFER/>
+ <pbcast.FLUSH timeout="0"/>
+</config>
+
+
+ As it shows, the file content defines a jgroups protocol stacks. If you want hornetq
+ to use this stacks for channel creation, you have to make sure the value of
+ jgroups-file in your broadcast-group/discovery-group configuration
+ to be the name of this jgroups configuration file. For example if the above stacks
+ configuration is stored in a file named "jgroups-stacks.xml" then your
+ jgroups-file should be like
+
+<jgroups-file>jgroups-stacks.xml</jgroups-file>
+
+
+
+ Discovery Groups
+ While the broadcast group defines how connector information is broadcasted from a
+ server, a discovery group defines how connector information is received from a
+ broadcast endpoint (a UDP multicast address or JGroup channel).
+ A discovery group maintains a list of connector pairs - one for each broadcast by
+ a different server. As it receives broadcasts on the broadcast endpoint from a
+ particular server it updates its entry in the list for that server.
+ If it has not received a broadcast from a particular server for a length of time
+ it will remove that server's entry from its list.
+ Discovery groups are used in two places in HornetQ:
+
+
+ By cluster connections so they know how to obtain an initial connection to download the topology
+
+
+ By messaging clients so they know how to obtain an initial connection to download the topology
+
+
+
+ Although a discovery group will always accept broadcasts, its current list of available live and
+ backup servers is only ever used when an initial connection is made, from then server discovery is
+ done over the normal HornetQ connections.
+
+
+
+ Each discovery group must be configured with broadcast endpoint (UDP or JGroups) that matches its broadcast
+ group counterpart. For example, if broadcast is configured using UDP, the discovery group must also use UDP, and the same
+ multicast address.
+
+
+
+
+ Defining Discovery Groups on the Server
+ For cluster connections, discovery groups are defined in the server side
+ configuration file hornetq-configuration.xml. All discovery
+ groups must be defined inside a discovery-groups element. There
+ can be many discovery groups defined by HornetQ server. Let's look at an
+ example:
+
+<discovery-groups>
+ <discovery-group name="my-discovery-group">
+ <local-bind-address>172.16.9.7</local-bind-address>
+ <group-address>231.7.7.7</group-address>
+ <group-port>9876</group-port>
+ <refresh-timeout>10000</refresh-timeout>
+ </discovery-group>
+</discovery-groups>
+ We'll consider each parameter of the discovery group:
+
+
+ name attribute. Each discovery group must have a unique
+ name per server.
+
+
+ local-bind-address. If you are running with multiple network interfaces on the same machine, you
+ may want to specify that the discovery group listens only only a specific interface. To do this you can specify the interface
+ address with this parameter. This parameter is optional. This is a UDP specific attribute.
+
+
+ group-address. This is the multicast IP address of the
+ group to listen on. It should match the group-address in
+ the broadcast group that you wish to listen from. This parameter is
+ mandatory. This is a UDP specific attribute.
+
+
+ group-port. This is the UDP port of the multicast
+ group. It should match the group-port in the broadcast
+ group that you wish to listen from. This parameter is mandatory. This is a UDP specific attribute.
+
+
+ refresh-timeout. This is the period the discovery group
+ waits after receiving the last broadcast from a particular server before
+ removing that servers connector pair entry from its list. You would normally
+ set this to a value significantly higher than the broadcast-period on the broadcast group otherwise servers
+ might intermittently disappear from the list even though they are still
+ broadcasting due to slight differences in timing. This parameter is
+ optional, the default value is 10000 milliseconds (10
+ seconds).
+
+
+ Here is another example that defines a JGroups discovery group:
+
+<discovery-groups>
+ <discovery-group name="my-broadcast-group">
+ <jgroups-file>test-jgroups-file_ping.xml</jgroups-file>
+ <jgroups-channel>hornetq_broadcast_channel</jgroups-channel>
+ <refresh-timeout>10000</refresh-timeout>
+ </discovery-group>
+</discovery-groups>
+ To receive broadcast from JGroups channels, one must specify two attributes,
+ jgroups-file and jgroups-channel, as discussed
+ in details as following:
+
+
+ jgroups-file attribute. This is the name of JGroups configuration
+ file. It will be used to initialize JGroups channels. Make sure the file is in the
+ java resource path so that HornetQ can load it.
+
+
+ jgroups-channel attribute. The name that JGroups channels connect
+ to for receiving broadcasts.
+
+
+
+ The JGroups attributes (jgroups-file and jgroups-channel)
+ and UDP specific attributes described above are exclusive of each other. Only one set can be
+ specified in a discovery group configuration. Don't mix them!
+
+
+
+ Discovery Groups on the Client Side
+ Let's discuss how to configure a HornetQ client to use discovery to discover a
+ list of servers to which it can connect. The way to do this differs depending on
+ whether you're using JMS or the core API.
+
+ Configuring client discovery using JMS
+ If you're using JMS and you're also using the JMS Service on the server to
+ load your JMS connection factory instances into JNDI, then you can specify which
+ discovery group to use for your JMS connection factory in the server side xml
+ configuration hornetq-jms.xml. Let's take a look at an
+ example:
+
+<connection-factory name="ConnectionFactory">
+ <discovery-group-ref discovery-group-name="my-discovery-group"/>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+</connection-factory>
+ The element discovery-group-ref specifies the name of a
+ discovery group defined in hornetq-configuration.xml.
+ When this connection factory is downloaded from JNDI by a client application
+ and JMS connections are created from it, those connections will be load-balanced
+ across the list of servers that the discovery group maintains by listening on
+ the multicast address specified in the discovery group configuration.
+ If you're using JMS, but you're not using JNDI to lookup a connection factory
+ - you're instantiating the JMS connection factory directly then you can specify
+ the discovery group parameters directly when creating the JMS connection
+ factory. Here's an
+ example:
+
+final String groupAddress = "231.7.7.7";
+
+final int groupPort = 9876;
+
+ConnectionFactory jmsConnectionFactory =
+HornetQJMSClient.createConnectionFactory(new DiscoveryGroupConfiguration(groupAddress, groupPort,
+ new UDPBroadcastGroupConfiguration(groupAddress, groupPort, null, -1)), JMSFactoryType.CF);
+
+Connection jmsConnection1 = jmsConnectionFactory.createConnection();
+
+Connection jmsConnection2 = jmsConnectionFactory.createConnection();
+ The refresh-timeout can be set directly on the DiscoveryGroupConfiguration
+ by using the setter method setDiscoveryRefreshTimeout() if you
+ want to change the default value.
+ There is also a further parameter settable on the DiscoveryGroupConfiguration using the
+ setter method setDiscoveryInitialWaitTimeout(). If the connection
+ factory is used immediately after creation then it may not have had enough time
+ to received broadcasts from all the nodes in the cluster. On first usage, the
+ connection factory will make sure it waits this long since creation before
+ creating the first connection. The default value for this parameter is 10000 milliseconds.
+
+
+ Configuring client discovery using Core
+ If you're using the core API to directly instantiate
+ ClientSessionFactory instances, then you can specify the
+ discovery group parameters directly when creating the session factory. Here's an
+ example:
+
+final String groupAddress = "231.7.7.7";
+final int groupPort = 9876;
+ServerLocator factory = HornetQClient.createServerLocatorWithHA(new DiscoveryGroupConfiguration(groupAddress, groupPort,
+ new UDPBroadcastGroupConfiguration(groupAddress, groupPort, null, -1))));
+ClientSessionFactory factory = locator.createSessionFactory();
+ClientSession session1 = factory.createSession();
+ClientSession session2 = factory.createSession();
+ The refresh-timeout can be set directly on the DiscoveryGroupConfiguration
+ by using the setter method setDiscoveryRefreshTimeout() if you
+ want to change the default value.
+ There is also a further parameter settable on the DiscoveryGroupConfiguration using the
+ setter method setDiscoveryInitialWaitTimeout(). If the session factory
+ is used immediately after creation then it may not have had enough time to
+ received broadcasts from all the nodes in the cluster. On first usage, the
+ session factory will make sure it waits this long since creation before creating
+ the first session. The default value for this parameter is 10000 milliseconds.
+
+
+
+
+ Discovery using static Connectors
+ Sometimes it may be impossible to use UDP on the network you are using. In this case its
+ possible to configure a connection with an initial list if possible servers. This could be just
+ one server that you know will always be available or a list of servers where at least one will
+ be available.
+ This doesn't mean that you have to know where all your servers are going to be hosted, you
+ can configure these servers to use the reliable servers to connect to. Once they are connected
+ there connection details will be propagated via the server it connects to
+
+ Configuring a Cluster Connection
+ For cluster connections there is no extra configuration needed, you just need to make sure that any
+ connectors are defined in the usual manner, (see for more
+ information on connectors). These are then referenced by the cluster connection configuration.
+
+
+ Configuring a Client Connection
+ A static list of possible servers can also be used by a normal client.
+
+ Configuring client discovery using JMS
+ If you're using JMS and you're also using the JMS Service on the server to
+ load your JMS connection factory instances into JNDI, then you can specify which
+ connectors to use for your JMS connection factory in the server side xml
+ configuration hornetq-jms.xml. Let's take a look at an
+ example:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty-connector"/>
+ <connector-ref connector-name="netty-connector2"/>
+ <connector-ref connector-name="netty-connector3"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+</connection-factory>
+
+ The element connectors contains a list of pre defined connectors in the
+ hornetq-configuration.xml file. When this connection factory is downloaded
+ from JNDI by a client application and JMS connections are created from it, those connections will
+ be load-balanced across the list of servers defined by these connectors.
+
+
+ If you're using JMS, but you're not using JNDI to lookup a connection factory - you're instantiating
+ the JMS connection factory directly then you can specify the connector list directly when creating
+ the JMS connection factory. Here's an example:
+
+
+HashMap<String, Object> map = new HashMap<String, Object>();
+map.put("host", "myhost");
+map.put("port", "5445");
+TransportConfiguration server1 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map);
+HashMap<String, Object> map2 = new HashMap<String, Object>();
+map2.put("host", "myhost2");
+map2.put("port", "5446");
+TransportConfiguration server2 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map2);
+
+HornetQConnectionFactory cf = HornetQJMSClient.createConnectionFactoryWithHA(JMSFactoryType.CF, server1, server2);
+
+
+ Configuring client discovery using Core
+ If you are using the core API then the same can be done as follows:
+
+HashMap<String, Object> map = new HashMap<String, Object>();
+map.put("host", "myhost");
+map.put("port", "5445");
+TransportConfiguration server1 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map);
+HashMap<String, Object> map2 = new HashMap<String, Object>();
+map2.put("host", "myhost2");
+map2.put("port", "5446");
+TransportConfiguration server2 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map2);
+
+ServerLocator locator = HornetQClient.createServerLocatorWithHA(server1, server2);
+ClientSessionFactory factory = locator.createSessionFactory();
+ClientSession session = factory.createSession();
+
+
+
+
+
+ Server-Side Message Load Balancing
+ If cluster connections are defined between nodes of a cluster, then HornetQ will load
+ balance messages arriving at a particular node from a client.
+ Let's take a simple example of a cluster of four nodes A, B, C, and D arranged in a
+ symmetric cluster (described in
+ ). We have a queue called OrderQueue
+ deployed on each node of the cluster.
+ We have client Ca connected to node A, sending orders to the server. We have also have
+ order processor clients Pa, Pb, Pc, and Pd connected to each of the nodes A, B, C, D. If
+ no cluster connection was defined on node A, then as order messages arrive on node A
+ they will all end up in the OrderQueue on node A, so will only get
+ consumed by the order processor client attached to node A, Pa.
+ If we define a cluster connection on node A, then as ordered messages arrive on node A
+ instead of all of them going into the local OrderQueue instance, they
+ are distributed in a round-robin fashion between all the nodes of the cluster. The
+ messages are forwarded from the receiving node to other nodes of the cluster. This is
+ all done on the server side, the client maintains a single connection to node A.
+ For example, messages arriving on node A might be distributed in the following order
+ between the nodes: B, D, C, A, B, D, C, A, B, D. The exact order depends on the order
+ the nodes started up, but the algorithm used is round robin.
+ HornetQ cluster connections can be configured to always blindly load balance messages
+ in a round robin fashion irrespective of whether there are any matching consumers on
+ other nodes, but they can be a bit cleverer than that and also be configured to only
+ distribute to other nodes if they have matching consumers. We'll look at both these
+ cases in turn with some examples, but first we'll discuss configuring cluster
+ connections in general.
+
+ Configuring Cluster Connections
+ Cluster connections group servers into clusters so that messages can be load
+ balanced between the nodes of the cluster. Let's take a look at a typical cluster
+ connection. Cluster connections are always defined in hornetq-configuration.xml inside a cluster-connection element. There can be zero or more cluster
+ connections defined per HornetQ server.
+
+<cluster-connections>
+ <cluster-connection name="my-cluster">
+ <address>jms</address>
+ <connector-ref>netty-connector</connector-ref>
+ <check-period>1000</check-period>
+ <connection-ttl>5000</connection-ttl>
+ <min-large-message-size>50000</min-large-message-size>
+ <call-timeout>5000</call-timeout>
+ <retry-interval>500</retry-interval>
+ <retry-interval-multiplier>1.0</retry-interval-multiplier>
+ <max-retry-interval>5000</max-retry-interval>
+ <initial-connect-attempts>-1</initial-connect-attempts>
+ <reconnect-attempts>-1</reconnect-attempts>
+ <use-duplicate-detection>true</use-duplicate-detection>
+ <forward-when-no-consumers>false</forward-when-no-consumers>
+ <max-hops>1</max-hops>
+ <confirmation-window-size>32000</confirmation-window-size>
+ <call-failover-timeout>30000</call-failover-timeout>
+ <notification-interval>1000</notification-interval>
+ <notification-attempts>2</notification-attempts>
+ <discovery-group-ref discovery-group-name="my-discovery-group"/>
+ </cluster-connection>
+</cluster-connections>
+ In the above cluster connection all parameters have been explicitly specified. The following
+ shows all the available configuration options
+
+
+ address. Each cluster connection only applies to
+ messages sent to an address that starts with this value. Note: this does
+ not use wild-card matching.
+ In this case, this cluster connection will load balance messages sent to
+ address that start with jms. This cluster connection,
+ will, in effect apply to all JMS queues and topics since they map to core
+ queues that start with the substring "jms".
+ The address can be any value and you can have many cluster connections
+ with different values of address, simultaneously
+ balancing messages for those addresses, potentially to different clusters of
+ servers. By having multiple cluster connections on different addresses a
+ single HornetQ Server can effectively take part in multiple clusters
+ simultaneously.
+ Be careful not to have multiple cluster connections with overlapping
+ values of address, e.g. "europe" and "europe.news" since
+ this could result in the same messages being distributed between more than
+ one cluster connection, possibly resulting in duplicate deliveries.
+ This parameter is mandatory.
+
+
+ connector-ref. This is the connector which will be sent to other nodes in
+ the cluster so they have the correct cluster topology.
+ This parameter is mandatory.
+
+
+ check-period. The period (in milliseconds) used to check if the cluster connection
+ has failed to receive pings from another server. Default is 30000.
+
+
+ connection-ttl. This is how long a cluster connection should stay alive if it
+ stops receiving messages from a specific node in the cluster. Default is 60000.
+
+
+ min-large-message-size. If the message size (in bytes) is larger than this
+ value then it will be split into multiple segments when sent over the network to other cluster
+ members. Default is 102400.
+
+
+ call-timeout. When a packet is sent via a cluster connection and is a blocking
+ call, i.e. for acknowledgements, this is how long it will wait (in milliseconds) for the reply before
+ throwing an exception. Default is 30000.
+
+
+ retry-interval. We mentioned before that, internally,
+ cluster connections cause bridges to be created between the nodes of the
+ cluster. If the cluster connection is created and the target node has not
+ been started, or say, is being rebooted, then the cluster connections from
+ other nodes will retry connecting to the target until it comes back up, in
+ the same way as a bridge does.
+ This parameter determines the interval in milliseconds between retry
+ attempts. It has the same meaning as the retry-interval
+ on a bridge (as described in ).
+ This parameter is optional and its default value is 500
+ milliseconds.
+
+
+ retry-interval-multiplier. This is a multiplier used to increase the
+ retry-interval after each reconnect attempt, default is 1.
+
+
+ max-retry-interval. The maximum delay (in milliseconds) for retries.
+ Default is 2000.
+
+
+ initial-connect-attempts. The number of times the system will
+ try to connect a node in the cluster initially. If the max-retry is achieved this
+ node will be considered permanently down and the system will not route messages
+ to this node. Default is -1 (infinite retries).
+
+
+ reconnect-attempts. The number of times the system will
+ try to reconnect to a node in the cluster. If the max-retry is achieved this node will
+ be considered permanently down and the system will stop routing messages to this
+ node. Default is -1 (infinite retries).
+
+
+ use-duplicate-detection. Internally cluster connections
+ use bridges to link the nodes, and bridges can be configured to add a
+ duplicate id property in each message that is forwarded. If the target node
+ of the bridge crashes and then recovers, messages might be resent from the
+ source node. By enabling duplicate detection any duplicate messages will be
+ filtered out and ignored on receipt at the target node.
+ This parameter has the same meaning as use-duplicate-detection
+ on a bridge. For more information on duplicate detection, please see
+ . Default is true.
+
+
+ forward-when-no-consumers. This parameter determines
+ whether messages will be distributed round robin between other nodes of the
+ cluster regardless of whether or not there are matching or
+ indeed any consumers on other nodes.
+ If this is set to true then each incoming message will
+ be round robin'd even though the same queues on the other nodes of the
+ cluster may have no consumers at all, or they may have consumers that have
+ non matching message filters (selectors). Note that HornetQ will
+ not forward messages to other nodes if there are no
+ queues of the same name on the other nodes, even if
+ this parameter is set to true.
+ If this is set to false then HornetQ will only forward
+ messages to other nodes of the cluster if the address to which they are
+ being forwarded has queues which have consumers, and if those consumers have
+ message filters (selectors) at least one of those selectors must match the
+ message.
+ Default is false.
+
+
+ max-hops. When a cluster connection decides the set of
+ nodes to which it might load balance a message, those nodes do not have to
+ be directly connected to it via a cluster connection. HornetQ can be
+ configured to also load balance messages to nodes which might be connected
+ to it only indirectly with other HornetQ servers as intermediates in a
+ chain.
+ This allows HornetQ to be configured in more complex topologies and still
+ provide message load balancing. We'll discuss this more later in this
+ chapter.
+ The default value for this parameter is 1, which means
+ messages are only load balanced to other HornetQ serves which are directly
+ connected to this server. This parameter is optional.
+
+
+ confirmation-window-size. The size (in bytes) of the window
+ used for sending confirmations from the server connected to. So once the server has
+ received confirmation-window-size bytes it notifies its client,
+ default is 1048576. A value of -1 means no window.
+
+
+ call-failover-timeout. Similar to call-timeout but used
+ when a call is made during a failover attempt. Default is -1 (no timeout).
+
+
+ notification-interval. How often (in milliseconds) the cluster connection
+ should broadcast itself when attaching to the cluster. Default is 1000.
+
+
+ notification-attempts. How many times the cluster connection should
+ broadcast itself when connecting to the cluster. Default is 2.
+
+
+ discovery-group-ref. This parameter determines which
+ discovery group is used to obtain the list of other servers in the cluster
+ that this cluster connection will make connections to.
+
+
+
+ Alternatively if you would like your cluster connections to use a static list of
+ servers for discovery then you can do it like this.
+
+
+<cluster-connection name="my-cluster">
+ ...
+ <static-connectors>
+ <connector-ref>server0-connector</connector-ref>
+ <connector-ref>server1-connector</connector-ref>
+ </static-connectors>
+</cluster-connection>
+
+ Here we have defined 2 servers that we know for sure will that at least one will be available. There may
+ be many more servers in the cluster but these will; be discovered via one of these connectors once an
+ initial connection has been made.
+
+
+ Cluster User Credentials
+ When creating connections between nodes of a cluster to form a cluster connection,
+ HornetQ uses a cluster user and cluster password which is defined in hornetq-configuration.xml:
+
+<cluster-user>HORNETQ.CLUSTER.ADMIN.USER</cluster-user>
+<cluster-password>CHANGE ME!!</cluster-password>
+
+ It is imperative that these values are changed from their default, or remote
+ clients will be able to make connections to the server using the default values.
+ If they are not changed from the default, HornetQ will detect this and pester
+ you with a warning on every start-up.
+
+
+
+
+ Client-Side Load balancing
+ With HornetQ client-side load balancing, subsequent sessions created using a single
+ session factory can be connected to different nodes of the cluster. This allows sessions
+ to spread smoothly across the nodes of a cluster and not be "clumped" on any particular
+ node.
+ The load balancing policy to be used by the client factory is configurable. HornetQ
+ provides four out-of-the-box load balancing policies, and you can also implement your own
+ and use that.
+ The out-of-the-box policies are
+
+
+ Round Robin. With this policy the first node is chosen randomly then each
+ subsequent node is chosen sequentially in the same order.
+ For example nodes might be chosen in the order B, C, D, A, B, C, D, A, B or D,
+ A, B, C, D, A, B, C, D or C, D, A, B, C, D, A, B, C.
+ Use org.hornetq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy
+ as the <connection-load-balancing-policy-class-name>.
+
+
+ Random. With this policy each node is chosen randomly.
+ Use org.hornetq.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy
+ as the <connection-load-balancing-policy-class-name>.
+
+
+ Random Sticky. With this policy the first node is chosen randomly and then re-used for subsequent
+ connections.
+ Use org.hornetq.api.core.client.loadbalance.RandomStickyConnectionLoadBalancingPolicy
+ as the <connection-load-balancing-policy-class-name>.
+
+
+ First Element. With this policy the "first" (i.e. 0th) node is always returned.
+ Use org.hornetq.api.core.client.loadbalance.FirstElementConnectionLoadBalancingPolicy
+ as the <connection-load-balancing-policy-class-name>.
+
+
+ You can also implement your own policy by implementing the interface org.hornetq.api.core.client.loadbalance.ConnectionLoadBalancingPolicy
+ Specifying which load balancing policy to use differs whether you are using JMS or the
+ core API. If you don't specify a policy then the default will be used which is org.hornetq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy.
+ If you're using JMS, and you're using JNDI on the server to put your JMS connection
+ factories into JNDI, then you can specify the load balancing policy directly in the
+ hornetq-jms.xml configuration file on the server as follows:
+
+<connection-factory name="ConnectionFactory">
+ <discovery-group-ref discovery-group-name="my-discovery-group"/>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ <connection-load-balancing-policy-class-name>
+ org.hornetq.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy
+ </connection-load-balancing-policy-class-name>
+</connection-factory>
+ The above example would deploy a JMS connection factory that uses the random connection load
+ balancing policy.
+ If you're using JMS but you're instantiating your connection factory directly on the
+ client side then you can set the load balancing policy using the setter on the
+ HornetQConnectionFactory before using it:
+
+ConnectionFactory jmsConnectionFactory = HornetQJMSClient.createConnectionFactory(...);
+jmsConnectionFactory.setLoadBalancingPolicyClassName("com.acme.MyLoadBalancingPolicy");
+ If you're using the core API, you can set the load balancing policy directly on the
+ ServerLocator instance you are using:
+
+ServerLocator locator = HornetQClient.createServerLocatorWithHA(server1, server2);
+locator.setLoadBalancingPolicyClassName("com.acme.MyLoadBalancingPolicy");
+ The set of servers over which the factory load balances can be determined in one of
+ two ways:
+
+
+ Specifying servers explicitly
+
+
+ Using discovery.
+
+
+
+
+ Specifying Members of a Cluster Explicitly
+
+ Sometimes you want to explicitly define a cluster more explicitly, that is control which
+ server connect to each other in the cluster. This is typically used to form non symmetrical clusters
+ such as chain cluster or ring clusters. This can only be done using a static list of connectors and is
+ configured as follows:
+
+
+<cluster-connection name="my-cluster">
+ <address>jms</address>
+ <connector-ref>netty-connector</connector-ref>
+ <retry-interval>500</retry-interval>
+ <use-duplicate-detection>true</use-duplicate-detection>
+ <forward-when-no-consumers>true</forward-when-no-consumers>
+ <max-hops>1</max-hops>
+ <static-connectors allow-direct-connections-only="true">
+ <connector-ref>server1-connector</connector-ref>
+ </static-connectors>
+</cluster-connection>
+
+ In this example we have set the attribute allow-direct-connections-only which means that
+ the only server that this server can create a cluster connection to is server1-connector. This means you can
+ explicitly create any cluster topology you want.
+
+
+
+ Message Redistribution
+ Another important part of clustering is message redistribution. Earlier we learned how
+ server side message load balancing round robins messages across the cluster. If forward-when-no-consumers is false, then messages won't be forwarded to
+ nodes which don't have matching consumers, this is great and ensures that messages don't
+ arrive on a queue which has no consumers to consume them, however there is a situation
+ it doesn't solve: What happens if the consumers on a queue close after the messages have
+ been sent to the node? If there are no consumers on the queue the message won't get
+ consumed and we have a starvation situation.
+ This is where message redistribution comes in. With message redistribution HornetQ can
+ be configured to automatically redistribute messages from queues
+ which have no consumers back to other nodes in the cluster which do have matching
+ consumers.
+ Message redistribution can be configured to kick in immediately after the last
+ consumer on a queue is closed, or to wait a configurable delay after the last consumer
+ on a queue is closed before redistributing. By default message redistribution is
+ disabled.
+ Message redistribution can be configured on a per address basis, by specifying the
+ redistribution delay in the address settings, for more information on configuring
+ address settings, please see .
+ Here's an address settings snippet from hornetq-configuration.xml
+ showing how message redistribution is enabled for a set of queues:
+
+<address-settings>
+ <address-setting match="jms.#">
+ <redistribution-delay>0</redistribution-delay>
+ </address-setting>
+</address-settings>
+ The above address-settings block would set a redistribution-delay of 0 for any queue which is bound
+ to an address that starts with "jms.". All JMS queues and topic subscriptions are bound
+ to addresses that start with "jms.", so the above would enable instant (no delay)
+ redistribution for all JMS queues and topic subscriptions.
+ The attribute match can be an exact match or it can be a string
+ that conforms to the HornetQ wildcard syntax (described in ).
+ The element redistribution-delay defines the delay in milliseconds
+ after the last consumer is closed on a queue before redistributing messages from that
+ queue to other nodes of the cluster which do have matching consumers. A delay of zero
+ means the messages will be immediately redistributed. A value of -1
+ signifies that messages will never be redistributed. The default value is -1.
+ It often makes sense to introduce a delay before redistributing as it's a common case
+ that a consumer closes but another one quickly is created on the same queue, in such a
+ case you probably don't want to redistribute immediately since the new consumer will
+ arrive shortly.
+
+
+ Cluster topologies
+ HornetQ clusters can be connected together in many different topologies, let's
+ consider the two most common ones here
+
+ Symmetric cluster
+ A symmetric cluster is probably the most common cluster topology, and you'll be
+ familiar with if you've had experience of JBoss Application Server
+ clustering.
+ With a symmetric cluster every node in the cluster is connected to every other
+ node in the cluster. In other words every node in the cluster is no more than one
+ hop away from every other node.
+ To form a symmetric cluster every node in the cluster defines a cluster connection
+ with the attribute max-hops set to 1.
+ Typically the cluster connection will use server discovery in order to know what
+ other servers in the cluster it should connect to, although it is possible to
+ explicitly define each target server too in the cluster connection if, for example,
+ UDP is not available on your network.
+ With a symmetric cluster each node knows about all the queues that exist on all
+ the other nodes and what consumers they have. With this knowledge it can determine
+ how to load balance and redistribute messages around the nodes.
+ Don't forget this warning when creating a
+ symmetric cluster.
+
+
+ Chain cluster
+ With a chain cluster, each node in the cluster is not connected to every node in
+ the cluster directly, instead the nodes form a chain with a node on each end of the
+ chain and all other nodes just connecting to the previous and next nodes in the
+ chain.
+ An example of this would be a three node chain consisting of nodes A, B and C.
+ Node A is hosted in one network and has many producer clients connected to it
+ sending order messages. Due to corporate policy, the order consumer clients need to
+ be hosted in a different network, and that network is only accessible via a third
+ network. In this setup node B acts as a mediator with no producers or consumers on
+ it. Any messages arriving on node A will be forwarded to node B, which will in turn
+ forward them to node C where they can get consumed. Node A does not need to directly
+ connect to C, but all the nodes can still act as a part of the cluster.
+ To set up a cluster in this way, node A would define a cluster connection that
+ connects to node B, and node B would define a cluster connection that connects to
+ node C. In this case we only want cluster connections in one direction since we're
+ only moving messages from node A->B->C and never from C->B->A.
+ For this topology we would set max-hops to 2. With a value of 2 the knowledge of what queues and
+ consumers that exist on node C would be propagated from node C to node B to node A.
+ Node A would then know to distribute messages to node B when they arrive, even
+ though node B has no consumers itself, it would know that a further hop away is node
+ C which does have consumers.
+
+
+
+ Scaling Down
+ HornetQ supports scaling down a cluster with no message loss (even for non-durable messages). This is especially
+ useful in certain environments (e.g. the cloud) where the size of a cluster may change relatively frequently.
+ When scaling up a cluster (i.e. adding nodes) there is no risk of message loss, but when scaling down a cluster
+ (i.e. removing nodes) the messages on those nodes would be lost unless the broker sent them to another node in
+ the cluster. HornetQ can be configured to do just that.
+ The simplest way to enable this behavior is to set scale-down to
+ true. If the server is clustered and scale-down is
+ true then when the server is shutdown gracefully (i.e. stopped without crashing) it will find
+ another node in the cluster and send all of its messages (both durable and non-durable)
+ to that node. The messages are processed in order and go to the back of the respective
+ queues on the other node (just as if the messages were sent from an external client for the first time).
+ If more control over where the messages go is required then specify scale-down-group-name.
+ Messages will only be sent to another node in the cluster that uses the same scale-down-group-name
+ as the server being shutdown.
+
+ If cluster nodes are grouped together with different scale-down-group-name values beware.
+ If all the nodes in a single group are shut down then the messages from that node/group will be lost.
+
+ If the server is using multiple cluster-connection then use scale-down-clustername
+ to identify the name of the cluster-connection which should be used for scaling down.
+
+
diff --git a/docs/user-manual/en/configuration-index.xml b/docs/user-manual/en/configuration-index.xml
new file mode 100644
index 0000000000..b3cc162105
--- /dev/null
+++ b/docs/user-manual/en/configuration-index.xml
@@ -0,0 +1,705 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Configuration Reference
+ This section is a quick index for looking up configuration. Click on the element name to
+ go to the specific chapter.
+
+ Server Configuration
+
+ hornetq-configuration.xml
+ This is the main core server configuration file.
+
+ Server Configuration
+
+
+
+
+
+
+
+ Element Name
+ Element Type
+ Description
+ Default
+
+
+
+
+
+
+
+
+ hornetq-jms.xml
+ This is the configuration file used by the server side JMS service to load JMS
+ Queues, Topics and Connection Factories.
+
+ JMS Server Configuration
+
+
+
+
+
+
+
+ Element Name
+ Element Type
+ Description
+ Default
+
+
+
+
+
+ connection-factory
+
+ ConnectionFactory
+ a list of connection factories to create and add to JNDI
+
+
+
+
+
+
+
+ Continued..
+
+
+
+
+
+
+
+
+
+ connection-factory.signature (attribute)
+
+ String
+ Type of connection factory
+ generic
+
+
+
+ connection-factory.xa
+
+ Boolean
+ If it is a XA connection factory
+ false
+
+
+
+ connection-factory.auto-group
+
+ Boolean
+ whether or not message grouping is automatically used
+ false
+
+
+ connection-factory.connectors
+
+ String
+ A list of connectors used by the connection factory
+
+
+
+ connection-factory.connectors.connector-ref.connector-name (attribute)
+
+ String
+ Name of the connector to connect to the live server
+
+
+
+ connection-factory.discovery-group-ref.discovery-group-name (attribute)
+
+ String
+ Name of discovery group used by this connection factory
+
+
+
+
+
+ connection-factory.discovery-initial-wait-timeout
+
+ Long
+ the initial time to wait (in ms) for discovery groups to wait for
+ broadcasts
+ 10000
+
+
+
+ connection-factory.block-on-acknowledge
+
+ Boolean
+ whether or not messages are acknowledged synchronously
+ false
+
+
+
+ connection-factory.block-on-non-durable-send
+
+ Boolean
+ whether or not non-durable messages are sent synchronously
+ false
+
+
+
+ connection-factory.block-on-durable-send
+
+ Boolean
+ whether or not durable messages are sent synchronously
+ true
+
+
+ connection-factory.call-timeout
+ Long
+ the timeout (in ms) for remote calls
+ 30000
+
+
+
+ connection-factory.client-failure-check-period
+
+ Long
+ the period (in ms) after which the client will consider the
+ connection failed after not receiving packets from the
+ server
+ 30000
+
+
+
+ connection-factory.client-id
+
+ String
+ the pre-configured client ID for the connection factory
+ null
+
+
+
+
+ connection-factory.connection-load-balancing-policy-class-name
+
+ String
+ the name of the load balancing class
+ org.hornetq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy
+
+
+
+ connection-factory.connection-ttl
+
+ Long
+ the time to live (in ms) for connections
+ 1 * 60000
+
+
+
+ connection-factory.consumer-max-rate
+ Integer
+ the fastest rate a consumer may consume messages per
+ second
+ -1
+
+
+
+ connection-factory.consumer-window-size
+ Integer
+ the window size (in bytes) for consumer flow control
+ 1024 * 1024
+
+
+
+ connection-factory.dups-ok-batch-size
+ Integer
+ the batch size (in bytes) between acknowledgements when using
+ DUPS_OK_ACKNOWLEDGE mode
+ 1024 * 1024
+
+
+ connection-factory.failover-on-initial-connection
+ Boolean
+ whether or not to failover to backup on event that initial connection to live server fails
+ false
+
+
+
+ connection-factory.failover-on-server-shutdown
+ Boolean
+ whether or not to failover on server shutdown
+ false
+
+
+
+ connection-factory.min-large-message-size
+ Integer
+ the size (in bytes) before a message is treated as large
+ 100 * 1024
+
+
+
+ connection-factory.avoid-large-messages
+ Boolean
+ If compress large messages and send them as regular messages if possible
+ false
+
+
+ connection-factory.cache-large-message-client
+ Boolean
+ If true clients using this connection factory will hold the large
+ message body on temporary files.
+ false
+
+
+
+ connection-factory.pre-acknowledge
+ Boolean
+ whether messages are pre acknowledged by the server before
+ sending
+ false
+
+
+
+ connection-factory.producer-max-rate
+ Integer
+ the maximum rate of messages per second that can be sent
+ -1
+
+
+ connection-factory.producer-window-size
+ Integer
+ the window size in bytes for producers sending messages
+ 1024 * 1024
+
+
+
+ connection-factory.confirmation-window-size
+
+ Integer
+ the window size (in bytes) for reattachment confirmations
+ 1024 * 1024
+
+
+
+ connection-factory.reconnect-attempts
+
+ Integer
+ maximum number of retry attempts, -1 signifies infinite
+ 0
+
+
+
+ connection-factory.retry-interval
+
+ Long
+ the time (in ms) to retry a connection after failing
+ 2000
+
+
+
+ connection-factory.retry-interval-multiplier
+
+ Double
+ multiplier to apply to successive retry intervals
+ 1.0
+
+
+ connection-factory.max-retry-interval
+ Integer
+ The maximum retry interval in the case a retry-interval-multiplier has been specified
+ 2000
+
+
+
+ connection-factory.scheduled-thread-pool-max-size
+
+ Integer
+ the size of the scheduled thread pool
+ 5
+
+
+
+ connection-factory.thread-pool-max-size
+
+ Integer
+ the size of the thread pool
+ -1
+
+
+
+
+ connection-factory.transaction-batch-size
+
+ Integer
+ the batch size (in bytes) between acknowledgements when using a
+ transactional session
+ 1024 * 1024
+
+
+
+ connection-factory.use-global-pools
+
+ Boolean
+ whether or not to use a global thread pool for threads
+ true
+
+
+ queue
+ Queue
+ a queue to create and add to JNDI
+
+
+
+ queue.name
+ (attribute)
+ String
+ unique name of the queue
+
+
+
+ queue.entry
+ String
+ context where the queue will be bound in JNDI (there can be
+ many)
+
+
+
+ queue.durable
+ Boolean
+ is the queue durable?
+ true
+
+
+ queue.filter
+ String
+ optional filter expression for the queue
+
+
+
+ topic
+ Topic
+ a topic to create and add to JNDI
+
+
+
+ topic.name
+ (attribute)
+ String
+ unique name of the topic
+
+
+
+ topic.entry
+ String
+ context where the topic will be bound in JNDI (there can be
+ many)
+
+
+
+
+
+
+
+
+ Using Masked Passwords in Configuration Files
+ By default all passwords in HornetQ server's configuration files are in plain text form. This usually poses no security issues as those
+ files should be well protected from unauthorized accessing. However, in some circumstances a user doesn't want to expose its passwords to more
+ eyes than necessary.
+
+ HornetQ can be configured to use 'masked' passwords in its configuration files. A masked password is an obscure string representation
+ of a real password. To mask a password a user will use an 'encoder'. The encoder takes in the real password and outputs the masked version.
+ A user can then replace the real password in the configuration files with the new masked password.
+ When HornetQ loads a masked password, it uses a suitable 'decoder' to decode it into real password.
+
+ HornetQ provides a default password encoder and decoder. Optionally users can use or implement their own encoder and decoder for
+ masking the passwords.
+
+ Password Masking in Server Configuration File
+
+ The password masking property
+
+ The server configuration file has a property that defines the default masking behaviors over the entire file scope.
+
+ mask-password: this boolean type property indicates if a password should be masked or not. Set it to "true"
+ if you want your passwords masked. The default value is "false".
+
+
+ Specific masking behaviors
+
+ cluster-password
+
+ The nature of the value of cluster-password is subject to the value of property 'mask-password'. If it is true
+ the cluster-password is masked.
+
+
+ Passwords in connectors and acceptors
+
+ In the server configuration, Connectors and Acceptors sometimes needs to specify passwords. For example
+ if a users wants to use an SSL-enabled NettyAcceptor, it can specify a key-store-password and a trust-store-password. Because
+ Acceptors and Connectors are pluggable implementations, each transport will have different password masking needs.
+
+ When a Connector or Acceptor configuration is initialised, HornetQ will add the "mask-password" and
+ "password-codec" values to the Connector or Acceptors params using the keys hornetq.usemaskedpassword
+ and hornetq.passwordcodec respectively. The Netty and InVM implementations will use these
+ as needed and any other implementations will have access to these to use if they so wish.
+
+
+ Passwords in Core Bridge configurations
+
+ Core Bridges are configured in the server configuration file and so the masking of its 'password' properties
+ follows the same rules as that of 'cluster-password'.
+
+
+
+ Examples
+
+ The following table summarizes the relations among the above-mentioned properties
+
+
+
+
+
+
+
+
+
+ mask-password
+ cluster-password
+ acceptor/connector passwords
+ bridge password
+
+
+
+
+ absent
+ plain text
+ plain text
+ plain text
+
+
+ false
+ plain text
+ plain text
+ plain text
+
+
+ true
+ masked
+ masked
+ masked
+
+
+
+
+
+Examples
+
+Note: In the following examples if related attributed or properties are absent, it means they are not specified in the configure file.
+
+example 1
+
+
+<cluster-password>bbc</cluster-password>
+
+This indicates the cluster password is a plain text value ("bbc").
+
+example 2
+
+
+<mask-password>true</mask-password>
+<cluster-password>80cf731af62c290</cluster-password>
+
+ This indicates the cluster password is a masked value and HornetQ will use its built-in decoder to decode it. All other
+ passwords in the configuration file, Connectors, Acceptors and Bridges, will also use masked passwords.
+
+
+
+ JMS Bridge password masking
+
+ The JMS Bridges are configured and deployed as separate beans so they need separate configuration to control the password masking.
+ A JMS Bridge has two password parameters in its constructor, SourcePassword and TargetPassword. It uses the following two optional
+ properties to control their masking:
+
+ useMaskedPassword -- If set to "true" the passwords are masked. Default is false.
+ passwordCodec -- Class name and its parameters for the Decoder used to decode the masked password. Ignored if
+ useMaskedPassword is false. The format of this property is a full qualified class name optionally followed by key/value pairs,
+ separated by semi-colons. For example:
+
+
+<property name="useMaskedPassword">true</property>
+
+
+<property name="passwordCodec">com.foo.FooDecoder;key=value</property>
+
+ HornetQ will load this property and initialize the class with a parameter map containing the "key"->"value" pair.
+ If passwordCodec is not specified, the built-in decoder is used.
+
+
+
+ Masking passwords in HornetQ ResourceAdapters and MDB activation configurations
+
+ Both ra.xml and MDB activation configuration have a 'password' property that can be masked. They are controlled by the following two
+ optional Resource Adapter properties in ra.xml:
+
+ UseMaskedPassword -- If setting to "true" the passwords are masked. Default is false.
+ PasswordCodec -- Class name and its parameters for the Decoder used to decode the masked password.
+ Ignored if UseMaskedPassword is false. The format of this property is a full qualified class name optionally followed by key/value pairs.
+ It is the same format as that for JMS Bridges. Example:
+
+
+<config-property>
+ <config-property-name>UseMaskedPassword</config-property-name>
+ <config-property-type>boolean</config-property-type>
+ <config-property-value>true</config-property-value>
+</config-property>
+<config-property>
+ <config-property-name>PasswordCodec</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>com.foo.ADecoder;key=helloworld</config-property-value>
+</config-property>
+
+ With this configuration, both passwords in ra.xml and all of its MDBs will have to be in masked form.
+
+
+
+ Masking passwords in hornetq-users.xml
+
+ HornetQ's built-in security manager uses plain configuration files where the user passwords are specified in plaintext
+ forms by default. To mask those parameters the following two properties are needed:
+
+ mask-password -- If set to "true" all the passwords are masked. Default is false.
+ password-codec -- Class name and its parameters for the Decoder used to decode the masked password.
+ Ignored if mask-password is false. The format of this property is a full qualified class name optionally
+ followed by key/value pairs. It is the same format as that for JMS Bridges. Example:
+
+
+<mask-password>true</mask-password>
+<password-codec>org.hornetq.utils.DefaultSensitiveStringCodec;key=hello world</password-codec>
+
+ When so configured, the HornetQ security manager will initialize a DefaultSensitiveStringCodec with the parameters
+ "key"->"hello world", then use it to decode all the masked passwords in this configuration file.
+
+
+
+ Choosing a decoder for password masking
+
+ As described in the previous sections, all password masking requires a decoder. A decoder uses an algorithm to
+ convert a masked password into its original clear text form in order to be used in various security operations. The algorithm
+ used for decoding must match that for encoding. Otherwise the decoding may not be successful.
+
+ For user's convenience HornetQ provides a default built-in Decoder. However a user can if they so wish implement their own.
+
+ The built-in Decoder
+
+ Whenever no decoder is specified in the configuration file, the built-in decoder is used. The class name for the built-in
+ decoder is org.hornetq.utils.DefaultSensitiveStringCodec. It has both encoding and decoding capabilities. It uses java.crypto.Cipher
+ utilities to encrypt (encode) a plaintext password and decrypt a mask string using same algorithm. Using this decoder/encoder is
+ pretty straightforward. To get a mask for a password, just run the following in command line:
+
+
+java org.hornetq.utils.DefaultSensitiveStringCodec "your plaintext password"
+
+ Make sure the classpath is correct. You'll get something like
+
+
+Encoded password: 80cf731af62c290
+
+ Just copy "80cf731af62c290" and replace your plaintext password with it.
+
+
+ Using a different decoder
+
+ It is possible to use a different decoder rather than the built-in one. Simply make sure the decoder
+ is in HornetQ's classpath and configure the server to use it as follows:
+
+
+<password-codec>com.foo.SomeDecoder;key1=value1;key2=value2</password-codec>
+
+ If your decoder needs params passed to it you can do this via key/value pairs when configuring.
+ For instance if your decoder needs say a "key-location" parameter, you can define like so:
+
+
+<password-codec>com.foo.NewDecoder;key-location=/some/url/to/keyfile</password-codec>
+
+ Then configure your cluster-password like this:
+
+
+<mask-password>true</mask-password>
+<cluster-password>masked_password</cluster-password>
+
+ When HornetQ reads the cluster-password it will initialize the NewDecoder and use it to decode "mask_password".
+ It also process all passwords using the new defined decoder.
+
+
+ Implementing your own codecs
+
+ To use a different decoder than the built-in one, you either pick one from existing libraries or you implement it yourself.
+ All decoders must implement the org.hornetq.utils.SensitiveDataCodec<T> interface:
+
+
+public interface SensitiveDataCodec<T>
+{
+ T decode(Object mask) throws Exception;
+
+ void init(Map<String, String> params);
+}
+
+ This is a generic type interface but normally for a password you just need String type.
+ So a new decoder would be defined like
+
+
+public class MyNewDecoder implements SensitiveDataCodec<String>
+{
+ public String decode(Object mask) throws Exception
+ {
+ //decode the mask into clear text password
+ return "the password";
+ }
+
+ public void init(Map<String, String> params)
+ {
+ //initialization done here. It is called right after the decoder has been created.
+ }
+}
+
+ Last but not least, once you get your own decoder, please add it to the classpath. Otherwise HornetQ will
+ fail to load it!
+
+
+
+
+
diff --git a/docs/user-manual/en/configuring-transports.xml b/docs/user-manual/en/configuring-transports.xml
new file mode 100644
index 0000000000..066e783834
--- /dev/null
+++ b/docs/user-manual/en/configuring-transports.xml
@@ -0,0 +1,453 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Configuring the Transport
+ HornetQ has a fully pluggable and highly flexible transport layer and defines its own
+ Service Provider Interface (SPI) to make plugging in a new transport provider relatively
+ straightforward.
+ In this chapter we'll describe the concepts required for understanding HornetQ transports
+ and where and how they're configured.
+
+ Understanding Acceptors
+ One of the most important concepts in HornetQ transports is the
+ acceptor. Let's dive straight in and take a look at an acceptor
+ defined in xml in the configuration file hornetq-configuration.xml.
+
+<acceptors>
+ <acceptor name="netty">
+ <factory-class>
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+ </factory-class>
+ <param key="port" value="5446"/>
+ </acceptor>
+</acceptors>
+ Acceptors are always defined inside an acceptors element. There can
+ be one or more acceptors defined in the acceptors element. There's no
+ upper limit to the number of acceptors per server.
+ Each acceptor defines a way in which connections can be made to the HornetQ
+ server.
+ In the above example we're defining an acceptor that uses Netty to listen for connections at port
+ 5446.
+ The acceptor element contains a sub-element factory-class, this element defines the factory used to create acceptor
+ instances. In this case we're using Netty to listen for connections so we use the Netty
+ implementation of an AcceptorFactory to do this. Basically, the
+ factory-class element determines which pluggable transport we're
+ going to use to do the actual listening.
+ The acceptor element can also be configured with zero or more
+ param sub-elements. Each param element defines
+ a key-value pair. These key-value pairs are used to configure the specific transport,
+ the set of valid key-value pairs depends on the specific transport be used and are
+ passed straight through to the underlying transport.
+ Examples of key-value pairs for a particular transport would be, say, to configure the
+ IP address to bind to, or the port to listen at.
+ Note that unlike versions before 2.4 an Acceptor can now support multiple protocols. By default this will
+ be all available protocols but can be limited by either the now deprecated protocol param or
+ by setting a comma seperated list to the newly added protocols parameter.
+
+
+ Understanding Connectors
+ Whereas acceptors are used on the server to define how we accept connections,
+ connectors are used by a client to define how it connects to a server.
+ Let's look at a connector defined in our hornetq-configuration.xml
+ file:
+
+<connectors>
+ <connector name="netty">
+ <factory-class>
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+ </factory-class>
+ <param key="port" value="5446"/>
+ </connector>
+</connectors>
+ Connectors can be defined inside a connectors element. There can be
+ one or more connectors defined in the connectors element. There's no
+ upper limit to the number of connectors per server.
+ You make ask yourself, if connectors are used by the client to
+ make connections then why are they defined on the server? There are
+ a couple of reasons for this:
+
+
+ Sometimes the server acts as a client itself when it connects to another
+ server, for example when one server is bridged to another, or when a server
+ takes part in a cluster. In this cases the server needs to know how to connect
+ to other servers. That's defined by connectors.
+
+
+ If you're using JMS and the server side JMS service to instantiate JMS
+ ConnectionFactory instances and bind them in JNDI, then when creating the
+ HornetQConnectionFactory it needs to know what server
+ that connection factory will create connections to.
+ That's defined by the connector-ref element in the hornetq-jms.xml file on the server side. Let's take a look at a
+ snipped from a hornetq-jms.xml file that shows a JMS
+ connection factory that references our netty connector defined in our hornetq-configuration.xml file:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ <entry name="XAConnectionFactory"/>
+ </entries>
+</connection-factory>
+
+
+
+
+ Configuring the transport directly from the client side.
+ How do we configure a core ClientSessionFactory with the
+ information that it needs to connect with a server?
+ Connectors are also used indirectly when directly configuring a core ClientSessionFactory to directly talk to a server. Although in this case
+ there's no need to define such a connector in the server side configuration, instead we
+ just create the parameters and tell the ClientSessionFactory which
+ connector factory to use.
+ Here's an example of creating a ClientSessionFactory which will
+ connect directly to the acceptor we defined earlier in this chapter, it uses the
+ standard Netty TCP transport and will try and connect on port 5446 to localhost
+ (default):
+
+Map<String, Object> connectionParams = new HashMap<String, Object>();
+
+connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME,
+ 5446);
+
+TransportConfiguration transportConfiguration =
+ new TransportConfiguration(
+ "org.hornetq.core.remoting.impl.netty.NettyConnectorFactory",
+ connectionParams);
+
+ServerLocator locator = HornetQClient.createServerLocatorWithoutHA(transportConfiguration);
+
+ClientSessionFactory sessionFactory = locator.createClientSessionFactory();
+
+ClientSession session = sessionFactory.createSession(...);
+
+etc
+ Similarly, if you're using JMS, you can configure the JMS connection factory directly
+ on the client side without having to define a connector on the server side or define a
+ connection factory in hornetq-jms.xml:
+
+Map<String, Object> connectionParams = new HashMap<String, Object>();
+
+connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, 5446);
+
+TransportConfiguration transportConfiguration =
+ new TransportConfiguration(
+ "org.hornetq.core.remoting.impl.netty.NettyConnectorFactory",
+ connectionParams);
+
+ConnectionFactory connectionFactory = HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
+
+Connection jmsConnection = connectionFactory.createConnection();
+
+etc
+
+
+ Configuring the Netty transport
+ Out of the box, HornetQ currently uses Netty, a high performance low level network library.
+ Our Netty transport can be configured in several different ways; to use old (blocking)
+ Java IO, or NIO (non-blocking), also to use straightforward TCP sockets, SSL, or to
+ tunnel over HTTP or HTTPS..
+ We believe this caters for the vast majority of transport requirements.
+
+ Single Port Support
+ As of version 2.4 HornetQ now supports using a single port for all protocols, HornetQ will automatically
+ detect which protocol is being used CORE, AMQP or STOMP and use the appropriate HornetQ handler. It will also detect
+ whether protocols such as HTTP or Web Sockets are being used and also use the appropriate decoders
+ It is possible to limit which protocols are supported by using the protocols parameter
+ on the Acceptor like so:
+
+ <param key="protocols" value="CORE,AMQP"/>
+
+ The protocol parameter is now deprecated
+
+
+ Configuring Netty TCP
+ Netty TCP is a simple unencrypted TCP sockets based transport. Netty TCP can be
+ configured to use old blocking Java IO or non blocking Java NIO. We recommend you
+ use the Java NIO on the server side for better scalability with many concurrent
+ connections. However using Java old IO can sometimes give you better latency than
+ NIO when you're not so worried about supporting many thousands of concurrent
+ connections.
+ If you're running connections across an untrusted network please bear in mind this
+ transport is unencrypted. You may want to look at the SSL or HTTPS
+ configurations.
+ With the Netty TCP transport all connections are initiated from the client side.
+ I.e. the server does not initiate any connections to the client. This works well
+ with firewall policies that typically only allow connections to be initiated in one
+ direction.
+ All the valid Netty transport keys are defined in the class org.hornetq.core.remoting.impl.netty.TransportConstants. Most
+ parameters can be used either with acceptors or connectors, some only work with
+ acceptors. The following parameters can be used to configure Netty for simple
+ TCP:
+
+
+ use-nio. If this is true then Java
+ non blocking NIO will be used. If set to false then old
+ blocking Java IO will be used.
+ If you require the server to handle many concurrent connections, we highly
+ recommend that you use non blocking Java NIO. Java NIO does not maintain a
+ thread per connection so can scale to many more concurrent connections than
+ with old blocking IO. If you don't require the server to handle many
+ concurrent connections, you might get slightly better performance by using
+ old (blocking) IO. The default value for this property is false on the server side and false on the
+ client side.
+
+
+ host. This specifies the host name or IP address to
+ connect to (when configuring a connector) or to listen on (when configuring
+ an acceptor). The default value for this property is localhost. When configuring acceptors, multiple hosts or IP
+ addresses can be specified by separating them with commas. It is also
+ possible to specify 0.0.0.0 to accept connection from all the
+ host's network interfaces. It's not valid to specify multiple addresses when
+ specifying the host for a connector; a connector makes a connection to one
+ specific address.
+
+ Don't forget to specify a host name or IP address! If you want your
+ server able to accept connections from other nodes you must specify a
+ hostname or IP address at which the acceptor will bind and listen for
+ incoming connections. The default is localhost which of course is not
+ accessible from remote nodes!
+
+
+
+ port. This specified the port to connect to (when
+ configuring a connector) or to listen on (when configuring an acceptor). The
+ default value for this property is 5445.
+
+
+ tcp-no-delay. If this is true then
+ Nagle's
+ algorithm will be disabled. This is a
+ Java (client) socket option. The default value for this property is true.
+
+
+ tcp-send-buffer-size. This parameter determines the
+ size of the TCP send buffer in bytes. The default value for this property is
+ 32768 bytes (32KiB).
+ TCP buffer sizes should be tuned according to the bandwidth and latency of
+ your network. Here's a good link that explains the theory behind this.
+ In summary TCP send/receive buffer sizes should be calculated as:
+
+buffer_size = bandwidth * RTT.
+ Where bandwidth is in bytes per second and network
+ round trip time (RTT) is in seconds. RTT can be easily measured using the
+ ping utility.
+ For fast networks you may want to increase the buffer sizes from the
+ defaults.
+
+
+ tcp-receive-buffer-size. This parameter determines the
+ size of the TCP receive buffer in bytes. The default value for this property
+ is 32768 bytes (32KiB).
+
+
+ batch-delay. Before writing packets to the transport,
+ HornetQ can be configured to batch up writes for a maximum of batch-delay milliseconds. This can increase overall
+ throughput for very small messages. It does so at the expense of an increase
+ in average latency for message transfer. The default value for this property
+ is 0 ms.
+
+
+ direct-deliver. When a message arrives on the server
+ and is delivered to waiting consumers, by default, the delivery is done on
+ the same thread as that on which the message arrived. This gives good latency
+ in environments with relatively small messages and a small number of consumers,
+ but at the cost of overall throughput and scalability - especially on multi-core
+ machines. If you want the lowest latency and a possible reduction in throughput
+ then you can use the default value for direct-deliver (i.e.
+ true). If you are willing to take some small extra hit on latency but want the
+ highest throughput set direct-deliver to false
+ .
+
+
+ nio-remoting-threads. When configured to use NIO,
+ HornetQ will, by default, use a number of threads equal to three times the
+ number of cores (or hyper-threads) as reported by Runtime.getRuntime().availableProcessors() for processing
+ incoming packets. If you want to override this value, you can set the number
+ of threads by specifying this parameter. The default value for this
+ parameter is -1 which means use the value from Runtime.getRuntime().availableProcessors() * 3.
+
+
+ local-address. When configured a Netty Connector it is possible to specify
+ which local address the client will use when connecting to the remote address. This is typically used
+ in the Application Server or when running Embedded to control which address is used for outbound
+ connections. If the local-address is not set then the connector will use any local address available
+
+
+ local-port. When configured a Netty Connector it is possible to specify
+ which local port the client will use when connecting to the remote address. This is typically used
+ in the Application Server or when running Embedded to control which port is used for outbound
+ connections. If the local-port default is used, which is 0, then the connector will let the
+ system pick up an ephemeral port. valid ports are 0 to 65535
+
+
+
+
+ Configuring Netty SSL
+ Netty SSL is similar to the Netty TCP transport but it provides additional
+ security by encrypting TCP connections using the Secure Sockets Layer SSL
+ Please see the examples for a full working example of using Netty SSL.
+ Netty SSL uses all the same properties as Netty TCP but adds the following
+ additional properties:
+
+
+ ssl-enabled
+ Must be true to enable SSL. Default is false.
+
+
+ key-store-path
+ When used on an acceptor this is the path to the SSL key
+ store on the server which holds the server's certificates (whether self-signed
+ or signed by an authority).
+ When used on a connector this is the path to the client-side
+ SSL key store which holds the client certificates. This is only relevant
+ for a connector if you are using 2-way SSL (i.e. mutual
+ authentication). Although this value is configured on the server, it is
+ downloaded and used by the client. If the client needs to use a different path
+ from that set on the server then it can override the server-side setting by either
+ using the customary "javax.net.ssl.keyStore" system property or the HornetQ-specific
+ "org.hornetq.ssl.keyStore" system property. The HornetQ-specific system property
+ is useful if another component on client is already making use of the standard, Java
+ system property.
+
+
+ key-store-password
+ When used on an acceptor this is the password for the
+ server-side keystore.
+ When used on a connector this is the password for the
+ client-side keystore. This is only relevant for a connector
+ if you are using 2-way SSL (i.e. mutual authentication). Although this value can
+ be configured on the server, it is downloaded and used by the client. If the client
+ needs to use a different password from that set on the server then it can override
+ the server-side setting by either using the customary "javax.net.ssl.keyStorePassword"
+ system property or the HornetQ-specific "org.hornetq.ssl.keyStorePassword" system
+ property. The HornetQ-specific system property is useful if another component on client
+ is already making use of the standard, Java system property.
+
+
+ trust-store-path
+ When used on an acceptor this is the path to the server-side
+ SSL key store that holds the keys of all the clients that the server trusts. This
+ is only relevant for an acceptor if you are using 2-way SSL
+ (i.e. mutual authentication).
+ When used on a connector this is the path to the client-side
+ SSL key store which holds the public keys of all the servers that the client
+ trusts. Although this value can be configured on the server, it is downloaded and
+ used by the client. If the client needs to use a different path
+ from that set on the server then it can override the server-side setting by either
+ using the customary "javax.net.ssl.trustStore" system property or the HornetQ-specific
+ "org.hornetq.ssl.trustStore" system property. The HornetQ-specific system property
+ is useful if another component on client is already making use of the standard, Java
+ system property.
+
+
+ trust-store-password
+ When used on an acceptor this is the password for the
+ server-side trust store. This is only relevant for an acceptor
+ if you are using 2-way SSL (i.e. mutual authentication).
+ When used on a connector this is the password for the
+ client-side truststore. Although this value can be configured on the server, it is
+ downloaded and used by the client. If the client
+ needs to use a different password from that set on the server then it can override
+ the server-side setting by either using the customary "javax.net.ssl.trustStorePassword"
+ system property or the HornetQ-specific "org.hornetq.ssl.trustStorePassword" system
+ property. The HornetQ-specific system property is useful if another component on client
+ is already making use of the standard, Java system property.
+
+
+ enabled-cipher-suites
+ Whether used on an acceptor or connector this is a
+ comma separated list of cipher suites used for SSL communication. The default value is
+ null which means the JVM's default will be used.
+
+
+ enabled-protocols
+ Whether used on an acceptor or connector this is a
+ comma separated list of protocols used for SSL communication. The default value is
+ null which means the JVM's default will be used.
+
+
+ need-client-auth
+ This property is only for an acceptor. It tells a client connecting to this
+ acceptor that 2-way SSL is required. Valid values are true or
+ false. Default is false.
+
+
+
+
+ Configuring Netty HTTP
+ Netty HTTP tunnels packets over the HTTP protocol. It can be useful in scenarios
+ where firewalls only allow HTTP traffic to pass.
+ Please see the examples for a full working example of using Netty HTTP.
+ Netty HTTP uses the same properties as Netty TCP but adds the following additional
+ properties:
+
+
+ http-enabled. This is now no longer needed as of version 2.4. With single
+ port support HornetQ will now automatically detect if http is being used and configure itself.
+
+
+ http-client-idle-time. How long a client can be idle
+ before sending an empty http request to keep the connection alive
+
+
+ http-client-idle-scan-period. How often, in
+ milliseconds, to scan for idle clients
+
+
+ http-response-time. How long the server can wait before
+ sending an empty http response to keep the connection alive
+
+
+ http-server-scan-period. How often, in milliseconds, to
+ scan for clients needing responses
+
+
+ http-requires-session-id. If true the client will wait
+ after the first call to receive a session id. Used the http connector is
+ connecting to servlet acceptor (not recommended)
+
+
+
+
+ Configuring Netty Servlet
+ As of 2.4 HornetQ Servlet support will be provided via Undertow in Wildfly
+
+
+
diff --git a/docs/user-manual/en/connection-ttl.xml b/docs/user-manual/en/connection-ttl.xml
new file mode 100644
index 0000000000..b9b4182b98
--- /dev/null
+++ b/docs/user-manual/en/connection-ttl.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Detecting Dead Connections
+ In this section we will discuss connection time-to-live (TTL) and explain how HornetQ
+ deals with crashed clients and clients which have exited without cleanly closing their
+ resources.
+
+ Cleaning up Dead Connection Resources on the Server
+ Before a HornetQ client application exits it is considered good practice that it
+ should close its resources in a controlled manner, using a finally
+ block.
+ Here's an example of a well behaved core client application closing its session and
+ session factory in a finally block:
+
+ServerLocator locator = null;
+ClientSessionFactory sf = null;
+ClientSession session = null;
+
+try
+{
+ locator = HornetQClient.createServerLocatorWithoutHA(..);
+
+ sf = locator.createClientSessionFactory();;
+
+ session = sf.createSession(...);
+
+ ... do some stuff with the session...
+}
+finally
+{
+ if (session != null)
+ {
+ session.close();
+ }
+
+ if (sf != null)
+ {
+ sf.close();
+ }
+
+ if(locator != null)
+ {
+ locator.close();
+ }
+}
+ And here's an example of a well behaved JMS client application:
+
+Connection jmsConnection = null;
+
+try
+{
+ ConnectionFactory jmsConnectionFactory = HornetQJMSClient.createConnectionFactoryWithoutHA(...);
+
+ jmsConnection = jmsConnectionFactory.createConnection();
+
+ ... do some stuff with the connection...
+}
+finally
+{
+ if (connection != null)
+ {
+ connection.close();
+ }
+}
+ Unfortunately users don't always write well behaved applications, and sometimes
+ clients just crash so they don't have a chance to clean up their resources!
+ If this occurs then it can leave server side resources, like sessions, hanging on the
+ server. If these were not removed they would cause a resource leak on the server and
+ over time this result in the server running out of memory or other resources.
+ We have to balance the requirement for cleaning up dead client resources with the fact
+ that sometimes the network between the client and the server can fail and then come
+ back, allowing the client to reconnect. HornetQ supports client reconnection, so we
+ don't want to clean up "dead" server side resources too soon or this will prevent any
+ client from reconnecting, as it won't be able to find its old sessions on the
+ server.
+ HornetQ makes all of this configurable. For each ClientSessionFactory we define a connection TTL.
+ Basically, the TTL determines how long the server will keep a connection alive in the
+ absence of any data arriving from the client. The client will automatically send "ping"
+ packets periodically to prevent the server from closing it down. If the server doesn't
+ receive any packets on a connection for the connection TTL time, then it will
+ automatically close all the sessions on the server that relate to that
+ connection.
+ If you're using JMS, the connection TTL is defined by the ConnectionTTL attribute on a HornetQConnectionFactory
+ instance, or if you're deploying JMS connection factory instances direct into JNDI on
+ the server side, you can specify it in the xml config, using the parameter connection-ttl.
+ The default value for connection ttl on an "unreliable" connection (e.g. a Netty
+ connection) is 60000ms, i.e. 1 minute. The default value for connection
+ ttl on a "reliable" connection (e.g. an in-vm connection) is -1. A
+ value of -1 for ConnectionTTL means the server
+ will never time out the connection on the server side.
+ If you do not wish clients to be able to specify their own connection TTL, you can
+ override all values used by a global value set on the server side. This can be done by
+ specifying the connection-ttl-override attribute in the server side
+ configuration. The default value for connection-ttl-override is
+ -1 which means "do not override" (i.e. let clients use their own
+ values).
+
+ Closing core sessions or JMS connections that you have failed to close
+ As previously discussed, it's important that all core client sessions and JMS
+ connections are always closed explicitly in a finally block when
+ you are finished using them.
+ If you fail to do so, HornetQ will detect this at garbage collection time, and log
+ a warning similar to the following in the logs (If you are using JMS the warning
+ will involve a JMS connection not a client session):
+
+[Finalizer] 20:14:43,244 WARNING [org.hornetq.core.client.impl.DelegatingSession] I'm closing a ClientSession you left open. Please make sure you close all ClientSessions explicitly before let
+ting them go out of scope!
+[Finalizer] 20:14:43,244 WARNING [org.hornetq.core.client.impl.DelegatingSession] The session you didn't close was created here:
+java.lang.Exception
+ at org.hornetq.core.client.impl.DelegatingSession.<init>(DelegatingSession.java:83)
+ at org.acme.yourproject.YourClass (YourClass.java:666)
+ HornetQ will then close the connection / client session for you.
+ Note that the log will also tell you the exact line of your user code where you
+ created the JMS connection / client session that you later did not close. This will
+ enable you to pinpoint the error in your code and correct it appropriately.
+
+
+
+ Detecting failure from the client side.
+ In the previous section we discussed how the client sends pings to the server and how
+ "dead" connection resources are cleaned up by the server. There's also another reason
+ for pinging, and that's for the client to be able to detect that
+ the server or network has failed.
+ As long as the client is receiving data from the server it will consider the
+ connection to be still alive.
+ If the client does not receive any packets for client-failure-check-period milliseconds then it will consider the
+ connection failed and will either initiate failover, or call any FailureListener instances (or ExceptionListener
+ instances if you are using JMS) depending on how it has been configured.
+ If you're using JMS it's defined by the ClientFailureCheckPeriod
+ attribute on a HornetQConnectionFactory instance, or if you're
+ deploying JMS connection factory instances direct into JNDI on the server side, you can
+ specify it in the hornetq-jms.xml configuration file, using the
+ parameter client-failure-check-period.
+ The default value for client failure check period on an "unreliable" connection (e.g.
+ a Netty connection) is 30000ms, i.e. 30 seconds. The default value
+ for client failure check period on a "reliable" connection (e.g. an in-vm connection)
+ is -1. A value of -1 means the client will never fail the
+ connection on the client side if no data is received from the server. Typically this is
+ much lower than connection TTL to allow clients to reconnect in case of transitory
+ failure.
+
+
+ Configuring Asynchronous Connection Execution
+ Most packets received on the server side are executed on the remoting thread. These packets
+ represent short-running operations and are always executed on the remoting thread for
+ performance reasons.
+ However, by default some kinds of packets are executed using a thread from a
+ thread pool so that the remoting thread is not tied up for too long. Please note that
+ processing operations asynchronously on another thread adds a little more latency. These packets
+ are:
+
+
+ org.hornetq.core.protocol.core.impl.wireformat.RollbackMessage
+
+
+ org.hornetq.core.protocol.core.impl.wireformat.SessionCloseMessage
+
+
+ org.hornetq.core.protocol.core.impl.wireformat.SessionCommitMessage
+
+
+ org.hornetq.core.protocol.core.impl.wireformat.SessionXACommitMessage
+
+
+ org.hornetq.core.protocol.core.impl.wireformat.SessionXAPrepareMessage
+
+
+ org.hornetq.core.protocol.core.impl.wireformat.SessionXARollbackMessage
+
+
+ To disable asynchronous connection execution, set the parameter
+ async-connection-execution-enabled in
+ hornetq-configuration.xml to false (default value is
+ true).
+
+
diff --git a/docs/user-manual/en/core-bridges.xml b/docs/user-manual/en/core-bridges.xml
new file mode 100644
index 0000000000..9004e7f755
--- /dev/null
+++ b/docs/user-manual/en/core-bridges.xml
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Core Bridges
+ 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.
+ 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.
+ 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.
+ 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.
+ Bridges can be configured to provide once and only once 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 ).
+
+ Although they have similar function, don't confuse core bridges with JMS
+ bridges!
+ 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 once and only once 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.
+
+
+ Configuring Bridges
+ Bridges are configured in hornetq-configuration.xml. Let's kick off
+ with an example (this is actually from the bridge example):
+
+<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>
+ 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.
+ Let's take a look at all the parameters in turn:
+
+
+ name attribute. All bridges must have a unique name in the
+ server.
+
+
+ queue-name. This is the unique name of the local queue that
+ the bridge consumes from, it's a mandatory parameter.
+ The queue must already exist by the time the bridge is instantiated at
+ start-up.
+
+ If you're using JMS then normally the JMS configuration hornetq-jms.xml is loaded after the core configuration file
+ hornetq-configuration.xml 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.
+
+
+
+ forwarding-address. 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.
+
+
+ filter-string. 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 .
+
+
+ transformer-class-name. An optional transformer-class-name
+ can be specified. This is the name of a user-defined class which implements the
+ org.hornetq.core.server.cluster.Transformer
+ interface.
+ If this is specified then the transformer's transform()
+ 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.
+
+
+ ha. 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 false.
+
+
+ retry-interval. 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 2000milliseconds.
+
+
+ retry-interval-multiplier. This optional parameter
+ determines determines a multiplier to apply to the time since the last retry to
+ compute the time to the next retry.
+ This allows you to implement an exponential backoff
+ between retry attempts.
+ Let's take an example:
+ If we set retry-intervalto 1000 ms and
+ we set retry-interval-multiplier to 2.0,
+ then, if the first reconnect attempt fails, we will wait 1000
+ ms then 2000 ms then 4000 ms between
+ subsequent reconnection attempts.
+ The default value is 1.0 meaning each reconnect attempt is
+ spaced at equal intervals.
+
+
+ initial-connect-attempts. This optional parameter determines the
+ total number of initial connect attempts the bridge will make before giving up and
+ shutting down. A value of -1 signifies an unlimited number of
+ attempts. The default value is -1.
+
+
+ reconnect-attempts. This optional parameter determines the
+ total number of reconnect attempts the bridge will make before giving up and
+ shutting down. A value of -1 signifies an unlimited number of
+ attempts. The default value is -1.
+
+
+ failover-on-server-shutdown. 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.
+ The bridge connector can specify both a live and a backup server, if it
+ specifies a backup server and this parameter is set to true
+ then if the target server is cleanly 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.
+ 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.
+ The default value for this parameter is false.
+
+
+ use-duplicate-detection. This optional parameter determines
+ whether the bridge will automatically insert a duplicate id property into each
+ message that it forwards.
+ 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.
+ This allows the bridge to provide a once and only once
+ delivery guarantee without using heavyweight methods such as XA (see for more information).
+ The default value for this parameter is true.
+
+
+ confirmation-window-size. This optional parameter
+ determines the confirmation-window-size to use for the
+ connection used to forward messages to the target node. This attribute is
+ described in section
+
+ 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 max-size-bytes to prevent the flow of
+ messages from ceasing.
+
+
+
+
+ user. 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 cluster-user
+ in hornetq-configuration.xml will be used.
+
+
+ password. 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 cluster-password in hornetq-configuration.xml
+ will be used.
+
+
+ static-connectors or discovery-group-ref.
+ Pick either of these options to connect the bridge to the target server.
+
+ The static-connectors is a list of connector-ref
+ elements pointing to connector elements defined elsewhere.
+ A connector 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 .
+
+ The discovery-group-ref element has one attribute -
+ discovery-group-name. This attribute points to a
+ discovery-group defined elsewhere. For more information about
+ what discovery-groups are and how to configure them, please see
+ .
+
+
+
+
+
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 0000000000..33d99cf6bb
Binary files /dev/null and b/docs/user-manual/en/diagrams/architecture-diagrams.odg differ
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 0000000000..495c672ecf
Binary files /dev/null and b/docs/user-manual/en/diagrams/ha-replicated-store.odg differ
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 0000000000..3b976924f4
Binary files /dev/null and b/docs/user-manual/en/diagrams/ha-shared-store.odg differ
diff --git a/docs/user-manual/en/diverts.xml b/docs/user-manual/en/diverts.xml
new file mode 100644
index 0000000000..3cddf094bd
--- /dev/null
+++ b/docs/user-manual/en/diverts.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+
+ Diverting and Splitting Message Flows
+ HornetQ allows you to configure objects called diverts with
+ some simple server configuration.
+ Diverts allow you to transparently divert messages routed to one address to some other
+ address, without making any changes to any client application logic.
+ Diverts can be exclusive, meaning that the message is diverted
+ to the new address, and does not go to the old address at all, or they can be
+ non-exclusive which means the message continues to go the old
+ address, and a copy of it is also sent to the new address.
+ Non-exclusive diverts can therefore be used for splitting message
+ flows, e.g. there may be a requirement to monitor every order sent to an order queue.
+ Diverts can also be configured to have an optional message filter. If specified then only
+ messages that match the filter will be diverted.
+ Diverts can also be configured to apply a Transformer. If specified,
+ all diverted messages will have the opportunity of being transformed by the Transformer.
+ A divert will only divert a message to an address on the same server,
+ 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.
+ 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.
+ Diverts are defined as xml in the hornetq-configuration.xml file. There can
+ be zero or more diverts in the file.
+ Please see for a full working
+ example showing you how to configure and use diverts.
+ Let's take a look at some divert examples:
+
+ Exclusive Divert
+ 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.
+ Here's some example xml configuration for an exclusive divert, it's taken from the
+ divert example:
+
+<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>
+ We define a divert called 'prices-divert' that will divert any
+ messages sent to the address 'jms.topic.priceUpdates' (this
+ corresponds to any messages sent to a JMS Topic called 'priceUpdates') to another local address 'jms.queue.priceForwarding' (this corresponds to a local JMS queue called
+ 'priceForwarding'
+ We also specify a message filter string so only messages with the message property
+ office with value New York 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.
+ 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.
+ 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.
+
+
+ Non-exclusive Divert
+ 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 copy of the message to
+ the new address. The original message continues to the old address
+ You can therefore think of non-exclusive diverts as splitting a
+ message flow.
+ 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:
+
+<divert name="order-divert">
+ <address>jms.queue.orders</address>
+ <forwarding-address>jms.topic.spyTopic</forwarding-address>
+ <exclusive>false</exclusive>
+</divert>
+ The above divert example takes a copy of every message sent to the address 'jms.queue.orders' (Which corresponds to a JMS Queue called 'orders') and sends it to a local address called 'jms.topic.SpyTopic' (which corresponds to a JMS Topic called 'SpyTopic').
+
+
diff --git a/docs/user-manual/en/duplicate-detection.xml b/docs/user-manual/en/duplicate-detection.xml
new file mode 100644
index 0000000000..c2577ff245
--- /dev/null
+++ b/docs/user-manual/en/duplicate-detection.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+
+ Duplicate Message Detection
+ 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.
+ 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.
+ 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.
+ 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.
+ 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!
+ To solve these issues HornetQ provides automatic duplicate messages detection for
+ messages sent to addresses.
+
+ Using Duplicate Detection for Message Sending
+ 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.
+
+ Using duplicate detection to move messages between nodes can give you the same
+ once and only once 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.
+
+ If you're sending messages in a transaction then you don't have to set the property
+ for every 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.
+ The name of the property that you set is given by the value of org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID, which
+ is _HQ_DUPL_ID
+ The value of the property can be of type byte[] or SimpleString if you're using the core API. If you're using JMS it must be
+ a String, and its value should be unique. An easy way of generating
+ a unique id is by generating a UUID.
+ Here's an example of setting the property using the core API:
+
+...
+
+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);
+
+...
+ And here's an example using the JMS API:
+
+...
+
+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);
+
+...
+
+
+ Configuring the Duplicate ID Cache
+ The server maintains caches of received values of the org.hornetq.core.message.impl.HDR_DUPLICATE_DETECTION_ID property
+ sent to each address. Each address has its own distinct cache.
+ The cache is a circular fixed size cache. If the cache has a maximum size of n elements, then the n + 1th id stored will overwrite
+ the 0th element in the cache.
+ The maximum size of the cache is configured by the parameter id-cache-size in hornetq-configuration.xml, the default
+ value is 2000 elements.
+ The caches can also be configured to persist to disk or not. This is configured by the
+ parameter persist-id-cache, also in hornetq-configuration.xml. If this is set to true then
+ each id will be persisted to permanent storage as they are received. The default value
+ for this parameter is true.
+
+ 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.
+
+
+
+ Duplicate Detection and Bridges
+ 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.
+ To configure a core bridge to add the duplicate id header, simply set the use-duplicate-detection to true when configuring a
+ bridge in hornetq-configuration.xml.
+ The default value for this parameter is true.
+ For more information on core bridges and how to configure them, please see
+ .
+
+
+ Duplicate Detection and Cluster Connections
+ 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.
+ To configure a cluster connection to add the duplicate id header, simply set the
+ use-duplicate-detection to true when
+ configuring a cluster connection in hornetq-configuration.xml.
+ The default value for this parameter is true.
+ For more information on cluster connections and how to configure them, please see .
+
+
diff --git a/docs/user-manual/en/embedding-hornetq.xml b/docs/user-manual/en/embedding-hornetq.xml
new file mode 100644
index 0000000000..e2bea3a8d8
--- /dev/null
+++ b/docs/user-manual/en/embedding-hornetq.xml
@@ -0,0 +1,271 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Embedding HornetQ
+
+ 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 directly instantiate HornetQ
+ clients and servers in its own application code to perform that
+ functionality. We call this embedding HornetQ.
+
+ 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.
+
+ 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.
+
+
+ Simple Config File Embedding
+
+ 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.
+
+
+ Core API Only
+ For instantiating a core HornetQ Server only, the steps are pretty
+ simple. The example requires that you have defined a configuration file
+ hornetq-configuration.xml in your
+ classpath:
+
+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();
+
+The EmbeddedHornetQ 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.
+
+
+
+ JMS API
+
+ JMS embedding is simple as well. This example requires that you
+ have defined the config files
+ hornetq-configuration.xml,
+ hornetq-jms.xml, and a
+ hornetq-users.xml if you have security enabled. Let's
+ also assume that a queue and connection factory has been defined in the
+ hornetq-jms.xml config file.
+
+
+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 ...
+ By default, the EmbeddedJMS
+ class will store component entries defined within your
+ hornetq-jms.xml file in an internal concurrent hash
+ map. The EmbeddedJMS.lookup() method returns
+ components stored in this map. If you want to use JNDI, call the
+ EmbeddedJMS.setContext() 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.
+
+
+
+
+ POJO instantiation - Embedding Programmatically
+
+ You can follow this step-by-step guide to programmatically embed the
+ core, non-JMS HornetQ Server instance:
+
+ 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 section.
+
+ The acceptors are configured through
+ ConfigurationImpl. Just add the
+ NettyAcceptorFactory on the transports the same way you
+ would through the main configuration file.
+
+
+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);
+
+ You need to instantiate an instance of
+ org.hornetq.api.core.server.embedded.EmbeddedHornetQ
+ and add the configuration object to it.
+
+
+import org.hornetq.api.core.server.HornetQ;
+import org.hornetq.core.server.embedded.EmbeddedHornetQ;
+
+...
+
+EmbeddedHornetQ server = new EmbeddedHornetQ();
+server.setConfiguration(config);
+
+server.start();
+
+ You also have the option of instantiating
+ HornetQServerImpl directly:
+
+
+HornetQServer server = new HornetQServerImpl(config);
+server.start();
+
+ 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:
+
+
+// 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();
+
+ Please see for an example which
+ shows how to setup and run HornetQ embedded with JMS.
+
+
+
+ Dependency Frameworks
+
+ You may also choose to use a dependency injection framework such as
+ JBoss Micro Container or Spring
+ Framework. See for more
+ details on Spring and HornetQ, but here's how you would do things with the
+ JBoss Micro Container.
+
+ HornetQ standalone uses JBoss Micro Container as the injection
+ framework. HornetQBootstrapServer and
+ hornetq-beans.xml which are part of the HornetQ
+ distribution provide a very complete implementation of what's needed to
+ bootstrap the server using JBoss Micro Container.
+
+ When using JBoss Micro Container, you need to provide an XML file
+ declaring the HornetQServer and
+ Configuration object, you can also inject a security
+ manager and a MBean server if you want, but those are optional.
+
+ A very basic XML Bean declaration for the JBoss Micro Container
+ would be:
+
+
+<?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>
+
+ HornetQBootstrapServer provides an easy
+ encapsulation of JBoss Micro Container.
+
+
+HornetQBootstrapServer bootStrap = new HornetQBootstrapServer(new String[] {"hornetq-beans.xml"});
+bootStrap.run();
+
+
diff --git a/docs/user-manual/en/examples.xml b/docs/user-manual/en/examples.xml
new file mode 100644
index 0000000000..cec40216f0
--- /dev/null
+++ b/docs/user-manual/en/examples.xml
@@ -0,0 +1,689 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Examples
+ The HornetQ distribution comes with over 70 run out-of-the-box examples demonstrating many
+ of the features.
+ The examples are available in the distribution, in the examples
+ directory. Examples are split into JMS and core examples. JMS examples show how a particular
+ feature can be used by a normal JMS client. Core examples show how the equivalent feature
+ can be used by a core messaging client.
+ A set of Java EE examples are also provided which need WildFly
+ installed to be able to run.
+
+ JMS Examples
+ To run a JMS example, simply cd into the appropriate example
+ directory and type mvn verify (For details please read the readme.html
+ in each example directory).
+ Here's a listing of the examples with a brief description.
+
+ JMS AeroGear
+ This example shows how you can send a message to a mobile device by leveraging
+ AeroGears push technology which provides support for different push notification technologies
+ like Google Cloud Messaging, Apple's APNs or Mozilla's SimplePush.
+
+
+ Applet
+ This example shows you how to send and receive JMS messages from an Applet.
+
+
+ Application-Layer Failover
+ HornetQ also supports Application-Layer failover, useful in the case that
+ replication is not enabled on the server side.
+ With Application-Layer failover, it's up to the application to register a JMS
+ ExceptionListener with HornetQ which will be called by
+ HornetQ in the event that connection failure is detected.
+ The code in the ExceptionListener then recreates the JMS
+ connection, session, etc on another node and the application can continue.
+ Application-layer failover is an alternative approach to High Availability (HA).
+ Application-layer failover differs from automatic failover in that some client side
+ coding is required in order to implement this. Also, with Application-layer
+ failover, since the old session object dies and a new one is created, any
+ uncommitted work in the old session will be lost, and any unacknowledged messages
+ might be redelivered.
+
+
+ Core Bridge Example
+ The bridge example demonstrates a core bridge deployed on one
+ server, which consumes messages from a local queue and forwards them to an address
+ on a second server.
+ Core bridges are used to create message flows between any two HornetQ servers
+ which are remotely separated. Core bridges are resilient and will cope with
+ temporary connection failure allowing them to be an ideal choice for forwarding over
+ unreliable connections, e.g. a WAN.
+
+
+ Browser
+ The browser example shows you how to use a JMS QueueBrowser with HornetQ.
+ Queues are a standard part of JMS, please consult the JMS 1.1 specification for
+ full details.
+ A QueueBrowser is used to look at messages on the queue
+ without removing them. It can scan the entire content of a queue or only messages
+ matching a message selector.
+
+
+ Client Kickoff
+ The client-kickoff example shows how to terminate client
+ connections given an IP address using the JMX management API.
+
+
+ Client side failover listener
+ The client-side-failoverlistener example shows how to register a listener to monitor
+ failover events
+
+
+ Client-Side Load-Balancing
+ The client-side-load-balancing example demonstrates how
+ sessions created from a single JMS Connection can
+ be created to different nodes of the cluster. In other words it demonstrates how
+ HornetQ does client-side load-balancing of sessions across the cluster.
+
+
+ Clustered Durable Subscription
+ This example demonstrates a clustered JMS durable subscription
+
+
+ Clustered Grouping
+ This is similar to the message grouping example except that it demonstrates it
+ working over a cluster. Messages sent to different nodes with the same group id will
+ be sent to the same node and the same consumer.
+
+
+ Clustered Queue
+ The clustered-queue example demonstrates a JMS queue deployed
+ on two different nodes. The two nodes are configured to form a cluster. We then
+ create a consumer for the queue on each node, and we create a producer on only one
+ of the nodes. We then send some messages via the producer, and we verify that both
+ consumers receive the sent messages in a round-robin fashion.
+
+
+ Clustering with JGroups
+ The clustered-jgroups example demonstrates how to form a two
+ node cluster using JGroups as its underlying topology discovery technique, rather than
+ the default UDP broadcasting. We then create a consumer for the queue on each node,
+ and we create a producer on only one of the nodes. We then send some messages via the
+ producer, and we verify that both consumers receive the sent messages in a round-robin fashion.
+
+
+ Clustered Standalone
+ The clustered-standalone example demonstrates how to configure
+ and starts 3 cluster nodes on the same machine to form a cluster. A subscriber for a
+ JMS topic is created on each node, and we create a producer on only one of the
+ nodes. We then send some messages via the producer, and we verify that the 3
+ subscribers receive all the sent messages.
+
+
+ Clustered Static Discovery
+ This example demonstrates how to configure a cluster using a list of connectors rather
+ than UDP for discovery
+
+
+ Clustered Static Cluster One Way
+ This example demonstrates how to set up a cluster where cluster connections are one way,
+ i.e. server A -> Server B -> Server C
+
+
+ Clustered Topic
+ The clustered-topic example demonstrates a JMS topic deployed
+ on two different nodes. The two nodes are configured to form a cluster. We then
+ create a subscriber on the topic on each node, and we create a producer on only one
+ of the nodes. We then send some messages via the producer, and we verify that both
+ subscribers receive all the sent messages.
+
+
+ Message Consumer Rate Limiting
+ With HornetQ you can specify a maximum consume rate at which a JMS MessageConsumer
+ will consume messages. This can be specified when creating or deploying the
+ connection factory.
+ If this value is specified then HornetQ will ensure that messages are never
+ consumed at a rate higher than the specified rate. This is a form of consumer
+ throttling.
+
+
+ Dead Letter
+ The dead-letter example shows you how to define and deal with
+ dead letter messages. Messages can be delivered unsuccessfully (e.g. if the
+ transacted session used to consume them is rolled back).
+ Such a message goes back to the JMS destination ready to be redelivered. However,
+ this means it is possible for a message to be delivered again and again without any
+ success and remain in the destination, clogging the system.
+ To prevent this, messaging systems define dead letter messages: after a specified
+ unsuccessful delivery attempts, the message is removed from the destination and put
+ instead in a dead letter destination where they can be consumed for further
+ investigation.
+
+
+ Delayed Redelivery
+ The delayed-redelivery example demonstrates how HornetQ can be
+ configured to provide a delayed redelivery in the case a message needs to be
+ redelivered.
+ Delaying redelivery can often be useful in the case that clients regularly fail or
+ roll-back. Without a delayed redelivery, the system can get into a "thrashing"
+ state, with delivery being attempted, the client rolling back, and delivery being
+ re-attempted in quick succession, using up valuable CPU and network
+ resources.
+
+
+ Divert
+ HornetQ diverts allow messages to be transparently "diverted" or copied from one
+ address to another with just some simple configuration defined on the server
+ side.
+
+
+ Durable Subscription
+ The durable-subscription example shows you how to use a durable
+ subscription with HornetQ. Durable subscriptions are a standard part of JMS, please
+ consult the JMS 1.1 specification for full details.
+ Unlike non-durable subscriptions, the key function of durable subscriptions is
+ that the messages contained in them persist longer than the lifetime of the
+ subscriber - i.e. they will accumulate messages sent to the topic even if there is
+ no active subscriber on them. They will also survive server restarts or crashes.
+ Note that for the messages to be persisted, the messages sent to them must be marked
+ as durable messages.
+
+
+ Embedded
+ The embedded example shows how to embed JMS
+ within your own code using POJO instantiation and no config files.
+
+
+ Embedded Simple
+ The embedded example shows how to embed JMS within your own code using regular HornetQ XML files.
+
+
+ Message Expiration
+ The expiry example shows you how to define and deal with
+ message expiration. Messages can be retained in the messaging system for a limited
+ period of time before being removed. JMS specification states that clients should
+ not receive messages that have been expired (but it does not guarantee this will not
+ happen).
+ HornetQ can assign an expiry address to a given queue so that when messages
+ are expired, they are removed from the queue and sent to the expiry address.
+ These "expired" messages can later be consumed from the expiry address for
+ further inspection.
+
+
+ HornetQ Resource Adapter example
+ This examples shows how to build the hornetq resource adapters a rar for deployment in other Application
+ Server's
+
+
+ HTTP Transport
+ The http-transport example shows you how to configure HornetQ
+ to use the HTTP protocol as its transport layer.
+
+
+ Instantiate JMS Objects Directly
+ Usually, JMS Objects such as ConnectionFactory, Queue and Topic instances are looked up from JNDI
+ before being used by the client code. This objects are called "administered objects"
+ in JMS terminology.
+ However, in some cases a JNDI server may not be available or desired. To come to
+ the rescue HornetQ also supports the direct instantiation of these administered
+ objects on the client side so you don't have to use JNDI for JMS.
+
+
+ Interceptor
+ HornetQ allows an application to use an interceptor to hook into the messaging
+ system. Interceptors allow you to handle various message events in HornetQ.
+
+
+ JAAS
+ The jaas example shows you how to configure HornetQ to use JAAS
+ for security. HornetQ can leverage JAAS to delegate user authentication and
+ authorization to existing security infrastructure.
+
+
+ JMS Auto Closable
+ The jms-auto-closeable example shows how JMS resources, such
+ as connections, sessions and consumers, in JMS 2 can be automatically closed on error.
+
+
+ JMS Completion Listener
+ The jms-completion-listener example shows how to send a message
+ asynchronously to HornetQ and use a CompletionListener to be notified of the Broker
+ receiving it.
+
+
+ JMS Bridge
+ The jms-brige example shows how to setup a bridge
+ between two standalone HornetQ servers.
+
+
+ JMS Context
+ The jms-context example shows how to send and receive a message
+ to a JMS Queue using HornetQ by using a JMS Context.
+ A JMSContext is part of JMS 2.0 and combines the JMS Connection and Session Objects
+ into a simple Interface.
+
+
+ JMS Shared Consumer
+ The jms-shared-consumer example shows you how can use shared
+ consumers to share a subscription on a topic. In JMS 1.1 this was not allowed and so caused
+ a scalability issue. In JMS 2 this restriction has been lifted so you can share the load
+ across different threads and connections.
+
+
+ JMX Management
+ The jmx example shows how to manage HornetQ using JMX.
+
+
+ Large Message
+ The large-message example shows you how to send and receive
+ very large messages with HornetQ. HornetQ 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.
+ Large messages are persisted on the server so they can survive a server restart.
+ In other words HornetQ doesn't just do a simple socket stream from the sender to the
+ consumer.
+
+
+ Last-Value Queue
+ The last-value-queue example shows you how to define and deal
+ with last-value queues. Last-value queues are special queues which discard any
+ messages when a newer message with the same value for a well-defined last-value
+ property is put in the queue. In other words, a last-value queue only retains the
+ last value.
+ A typical example for last-value queue is for stock prices, where you are only
+ interested by the latest price for a particular stock.
+
+
+ Management
+ The management example shows how to manage HornetQ using JMS
+ Messages to invoke management operations on the server.
+
+
+ Management Notification
+ The management-notification example shows how to receive
+ management notifications from HornetQ using JMS messages. HornetQ servers emit
+ management notifications when events of interest occur (consumers are created or
+ closed, addresses are created or deleted, security authentication fails,
+ etc.).
+
+
+ Message Counter
+ The message-counters example shows you how to use message
+ counters to obtain message information for a JMS queue.
+
+
+ Message Group
+ The message-group example shows you how to configure and use
+ message groups with HornetQ. Message groups allow you to pin messages so they are
+ only consumed by a single consumer. Message groups are sets of messages that has the
+ following characteristics:
+
+
+
+ Messages in a message group share the same group id, i.e. they have
+ same JMSXGroupID string property values
+
+
+ The consumer that receives the first message of a group will receive
+ all the messages that belongs to the group
+
+
+
+
+
+ Message Group
+ The message-group2 example shows you how to configure and use
+ message groups with HornetQ via a connection factory.
+
+
+ Message Priority
+ Message Priority can be used to influence the delivery order for messages.
+ It can be retrieved by the message's standard header field 'JMSPriority' as
+ defined in JMS specification version 1.1.
+ The value is of type integer, ranging from 0 (the lowest) to 9 (the highest). When
+ messages are being delivered, their priorities will effect their order of delivery.
+ Messages of higher priorities will likely be delivered before those of lower
+ priorities.
+ Messages of equal priorities are delivered in the natural order of their arrival
+ at their destinations. Please consult the JMS 1.1 specification for full
+ details.
+
+
+ Multiple Failover
+ This example demonstrates how to set up a live server with multiple backups
+
+
+ Multiple Failover Failback
+ This example demonstrates how to set up a live server with multiple backups but
+ forcing failover back to the original live server
+
+
+ No Consumer Buffering
+ By default, HornetQ consumers buffer messages from the server in a client side
+ buffer before you actually receive them on the client side. This improves
+ performance since otherwise every time you called receive() or had processed the
+ last message in a MessageListener onMessage() method, the HornetQ
+ client would have to go the server to request the next message, which would then get
+ sent to the client side, if one was available.
+ This would involve a network round trip for every message and reduce performance.
+ Therefore, by default, HornetQ pre-fetches messages into a buffer on each
+ consumer.
+ In some case buffering is not desirable, and HornetQ allows it to be switched off.
+ This example demonstrates that.
+
+
+ Non-Transaction Failover With Server Data Replication
+ The non-transaction-failover example demonstrates two servers coupled
+ as a live-backup pair for high availability (HA), and a client using a non-transacted
+ JMS session failing over from live to backup when the live server is
+ crashed.
+ HornetQ implements failover of client connections between
+ live and backup servers. This is implemented by the replication of state between
+ live and backup nodes. When replication is configured and a live node crashes, the
+ client connections can carry and continue to send and consume messages. When non-transacted
+ sessions are used, once and only once message delivery is not guaranteed and it is possible
+ that some messages will be lost or delivered twice.
+
+
+ Paging
+ The paging example shows how HornetQ can support huge queues
+ even when the server is running in limited RAM. It does this by transparently
+ paging messages to disk, and depaging
+ them when they are required.
+
+
+ Pre-Acknowledge
+ Standard JMS supports three acknowledgement modes:
+ AUTO_ACKNOWLEDGE, CLIENT_ACKNOWLEDGE, and DUPS_OK_ACKNOWLEDGE. For a full description on these modes please
+ consult the JMS specification, or any JMS tutorial.
+ All of these standard modes involve sending acknowledgements from the client to
+ the server. However in some cases, you really don't mind losing messages in event of
+ failure, so it would make sense to acknowledge the message on the server before
+ delivering it to the client. This example demonstrates how HornetQ allows this with
+ an extra acknowledgement mode.
+
+
+ Message Producer Rate Limiting
+ The producer-rte-limit example demonstrates how, with HornetQ,
+ you can specify a maximum send rate at which a JMS message producer will send
+ messages.
+
+
+ Proton Qpid
+ HornetQ can be configured to accept requests from any AMQP client that supports the
+ 1.0 version of the protocol. This proton-j example shows a simply
+ qpid java 1.0 client example.
+
+
+ Proton Ruby
+ HornetQ can be configured to accept requests from any AMQP client that supports the
+ 1.0 version of the protocol. This example shows a simply proton ruby client
+ that sends and receives messages
+
+
+ Queue
+ A simple example demonstrating a JMS queue.
+
+
+ Message Redistribution
+ The queue-message-redistribution example demonstrates message
+ redistribution between queues with the same name deployed in different nodes of a
+ cluster.
+
+
+ Queue Requestor
+ A simple example demonstrating a JMS queue requestor.
+
+
+ Queue with Message Selector
+ The queue-selector example shows you how to selectively consume
+ messages using message selectors with queue consumers.
+
+
+ Reattach Node example
+ The Reattach Node example shows how a client can try to reconnect to
+ the same server instead of failing the connection immediately and
+ notifying any user ExceptionListener objects. HornetQ can be configured to automatically
+ retry the connection, and reattach to the server when it becomes available again across
+ the network.
+
+
+ Replicated Failback example
+ An example showing how failback works when using replication, In this example a live server will replicate
+ all its Journal to a backup server as it updates it. When the live server crashes the backup takes over
+ from the live server and the client reconnects and carries on from where it left off.
+
+
+ Replicated Failback static example
+ An example showing how failback works when using replication, but this time with static connectors
+
+
+ Replicated multiple failover example
+ An example showing how to configure multiple backups when using replication
+
+
+ Replicated Failover transaction example
+ An example showing how failover works with a transaction when using replication
+
+
+ Request-Reply example
+ A simple example showing the JMS request-response pattern.
+
+
+ Rest example
+ An example showing how to use the HornetQ Rest API
+
+
+ Scheduled Message
+ The scheduled-message example shows you how to send a scheduled
+ message to a JMS Queue with HornetQ. Scheduled messages won't get delivered until a
+ specified time in the future.
+
+
+ Security
+ The security example shows you how configure and use role based
+ queue security with HornetQ.
+
+
+ Send Acknowledgements
+ The send-acknowledgements example shows you how to use
+ HornetQ's advanced asynchronous send acknowledgements feature
+ to obtain acknowledgement from the server that sends have been received and
+ processed in a separate stream to the sent messages.
+
+
+ Spring Integration
+ This example shows how to use embedded JMS using HornetQ's Spring integration.
+
+
+ SSL Transport
+ The ssl-enabled shows you how to configure SSL with HornetQ to
+ send and receive message.
+
+
+ Static Message Selector
+ The static-selector example shows you how to configure a
+ HornetQ core queue with static message selectors (filters).
+
+
+ Static Message Selector Using JMS
+ The static-selector-jms example shows you how to configure a
+ HornetQ queue with static message selectors (filters) using JMS.
+
+
+ Stomp
+ The stomp example shows you how to configure a
+ HornetQ server to send and receive Stomp messages.
+
+
+ Stomp1.1
+ The stomp example shows you how to configure a
+ HornetQ server to send and receive Stomp messages via a Stomp 1.1 connection.
+
+
+ Stomp1.2
+ The stomp example shows you how to configure a
+ HornetQ server to send and receive Stomp messages via a Stomp 1.2 connection.
+
+
+ Stomp Over Web Sockets
+ The stomp-websockets example shows you how to configure a
+ HornetQ server to send and receive Stomp messages directly from Web browsers (provided
+ they support Web Sockets).
+
+
+ Symmetric Cluster
+ The symmetric-cluster example demonstrates a symmetric cluster
+ set-up with HornetQ.
+ HornetQ has extremely flexible clustering which allows you to set-up servers in
+ many different topologies. The most common topology that you'll perhaps be familiar
+ with if you are used to application server clustering is a symmetric cluster.
+ With a symmetric cluster, the cluster is homogeneous, i.e. each node is configured
+ the same as every other node, and every node is connected to every other node in the
+ cluster.
+
+
+ Temporary Queue
+ A simple example demonstrating how to use a JMS temporary queue.
+
+
+ Topic
+ A simple example demonstrating a JMS topic.
+
+
+ Topic Hierarchy
+ HornetQ supports topic hierarchies. With a topic hierarchy you can register a
+ subscriber with a wild-card and that subscriber will receive any messages sent to an
+ address that matches the wild card.
+
+
+ Topic Selector 1
+ The topic-selector-example1 example shows you how to send
+ message to a JMS Topic, and subscribe them using selectors with HornetQ.
+
+
+ Topic Selector 2
+ The topic-selector-example2 example shows you how to
+ selectively consume messages using message selectors with topic consumers.
+
+
+ Transaction Failover
+ The transaction-failover example demonstrates two servers coupled
+ as a live-backup pair for high availability (HA), and a client using a transacted JMS
+ session failing over from live to backup when the live server is
+ crashed.
+ HornetQ implements failover of client connections between
+ live and backup servers. This is implemented by the sharing of a journal between the
+ servers. When a live node crashes, the
+ client connections can carry and continue to send and consume messages. When transacted
+ sessions are used, once and only once message delivery is guaranteed.
+
+
+ Failover Without Transactions
+ The stop-server-failover example demonstrates failover of the
+ JMS connection from one node to another when the live server crashes using a JMS
+ non-transacted session.
+
+
+ Transactional Session
+ The transactional example shows you how to use a transactional
+ Session with HornetQ.
+
+
+ XA Heuristic
+ The xa-heuristic example shows you how to make an XA heuristic
+ decision through HornetQ Management Interface. A heuristic decision is a unilateral
+ decision to commit or rollback an XA transaction branch after it has been
+ prepared.
+
+
+ XA Receive
+ The xa-receive example shows you how message receiving behaves
+ in an XA transaction in HornetQ.
+
+
+ XA Send
+ The xa-send example shows you how message sending behaves in an
+ XA transaction in HornetQ.
+
+
+ XA with Transaction Manager
+ The xa-with-jta example shows you how to use JTA interfaces to
+ control transactions with HornetQ.
+
+
+
+ Core API Examples
+ To run a core example, simply cd into the appropriate example
+ directory and type ant
+
+ Embedded
+ The embedded example shows how to embed the HornetQ server
+ within your own code.
+
+
+
+ Java EE Examples
+ Most of the Java EE examples can be run the following way. Simply navigate into the
+ appropriate example directory and type mvn verify. This will use Arquillian to run the Application
+ Server and deploy the application. Note that you must have WildFly installed and the JBOSS_HOME environment
+ variable set. Please refer to the examples documentation for further instructions.
+
+ When running the Java EE examples you may see warning messages in the WildFly log about incompatible client and
+ server versions. This is normal if a newer version of the HornetQ project is being used with a version of WildFly that
+ ships an older version of HornetQ. These examples should still complete without any functional errors.
+
+
+ EJB/JMS Transaction
+ An example that shows using an EJB and JMS together within a transaction.
+
+
+ Resource Adapter Configuration
+ This example demonstrates how to configure several properties on the HornetQ JCA
+ resource adaptor.
+
+
+ Resource Adapter Remote Server Configuration
+ This example demonstrates how to configure the HornetQ resource adapter to talk to a remote HornetQ server
+
+
+ JMS Bridge
+ An example demonstrating the use of the HornetQ JMS bridge.
+
+
+ MDB (Message Driven Bean)
+ A simple set of examples of message driven beans, including failover examples.
+
+
+ Servlet Transport
+ An example of how to use the HornetQ servlet transport.
+
+
+ Servlet SSL Transport
+ An example of how to use the HornetQ servlet transport over SSL.
+
+
+ XA Recovery
+ An example of how XA recovery works within the JBoss Application server using
+ HornetQ.
+
+
+
diff --git a/docs/user-manual/en/filter-expressions.xml b/docs/user-manual/en/filter-expressions.xml
new file mode 100644
index 0000000000..2cf7bd2762
--- /dev/null
+++ b/docs/user-manual/en/filter-expressions.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+
+ Filter Expressions
+ HornetQ provides a powerful filter language based on a subset of the SQL 92
+ expression syntax.
+ It is the same as the syntax used for JMS selectors, but the predefined identifiers are
+ different. For documentation on JMS selector syntax please the JMS javadoc for javax.jms.Message.
+ Filter expressions are used in several places in HornetQ
+
+
+ Predefined Queues. When pre-defining a queue, either in hornetq-configuration.xml or hornetq-jms.xml a filter
+ expression can be defined for a queue. Only messages that match the filter
+ expression will enter the queue.
+
+
+ Core bridges can be defined with an optional filter expression, only matching
+ messages will be bridged (see ).
+
+
+ Diverts can be defined with an optional filter expression, only matching messages
+ will be diverted (see ).
+
+
+ Filter are also used programmatically when creating consumers, queues and in
+ several places as described in .
+
+
+ There are some differences between JMS selector expressions and HornetQ core
+ filter expressions. Whereas JMS selector expressions operate on a JMS message, HornetQ
+ core filter expressions operate on a core message.
+ The following identifiers can be used in a core filter expressions to refer to attributes
+ of the core message in an expression:
+
+
+ HQPriority. To refer to the priority of a message. Message
+ priorities are integers with valid values from 0 - 9. 0 is the lowest priority and 9 is the highest.
+ E.g. HQPriority = 3 AND animal = 'aardvark'
+
+
+ HQExpiration. To refer to the expiration time of a message.
+ The value is a long integer.
+
+
+ HQDurable. To refer to whether a message is durable or not.
+ The value is a string with valid values: DURABLE or NON_DURABLE.
+
+
+ HQTimestamp. The timestamp of when the message was created.
+ The value is a long integer.
+
+
+ HQSize. The size of a message in bytes. The value is an
+ integer.
+
+
+ Any other identifiers used in core filter expressions will be assumed to be properties of
+ the message.
+
diff --git a/docs/user-manual/en/flow-control.xml b/docs/user-manual/en/flow-control.xml
new file mode 100644
index 0000000000..0de82760cc
--- /dev/null
+++ b/docs/user-manual/en/flow-control.xml
@@ -0,0 +1,316 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Flow Control
+ Flow control is used to limit the flow of data between a client and server, or a server and
+ another server in order to prevent the client or server being overwhelmed with data.
+
+ Consumer Flow Control
+ This controls the flow of data between the server and the client as the client consumes
+ messages. For performance reasons clients normally buffer messages before delivering to the
+ consumer via the receive() method or asynchronously via a message
+ listener. If the consumer cannot process messages as fast as they are being delivered and
+ stored in the internal buffer, then you could end up with a situation where messages would
+ keep building up possibly causing out of memory on the client if they cannot be processed
+ in time.
+
+ Window-Based Flow Control
+ By default, HornetQ consumers buffer messages from the server in a client side buffer
+ before the client consumes them. This improves performance: otherwise every time the
+ client consumes a message, HornetQ would have to go the server to request the next
+ message. In turn, this message would then get sent to the client side, if one was
+ available.
+ A network round trip would be involved for every message and
+ considerably reduce performance.
+ To prevent this, HornetQ pre-fetches messages into a buffer on each consumer. The
+ total maximum size of messages (in bytes) that will be buffered on each consumer is
+ determined by the consumer-window-size parameter.
+ By default, the consumer-window-size is set to 1 MiB (1024 * 1024
+ bytes).
+ The value can be:
+
+
+ -1 for an unbounded buffer
+
+
+ 0 to not buffer any messages. See for working example of a consumer
+ with no buffering.
+
+
+ >0 for a buffer with the given maximum size in
+ bytes.
+
+
+ Setting the consumer window size can considerably improve performance depending on
+ the messaging use case. As an example, let's consider the two extremes:
+
+
+ Fast consumers
+
+ Fast consumers can process messages as fast as they consume them (or even
+ faster)
+ To allow fast consumers, set the consumer-window-size to
+ -1. This will allow unbounded message buffering on the
+ client side.
+ Use this setting with caution: it can overflow the client memory if the
+ consumer is not able to process messages as fast as it receives them.
+
+
+
+ Slow consumers
+
+ Slow consumers takes significant time to process each message and it is
+ desirable to prevent buffering messages on the client side so that they can be
+ delivered to another consumer instead.
+ Consider a situation where a queue has 2 consumers; 1 of which is very slow.
+ Messages are delivered in a round robin fashion to both consumers, the fast
+ consumer processes all of its messages very quickly until its buffer is empty.
+ At this point there are still messages awaiting to be processed in the buffer
+ of the slow consumer thus preventing them being processed by the fast consumer.
+ The fast consumer is therefore sitting idle when it could be processing the
+ other messages.
+ To allow slow consumers, set the consumer-window-size to
+ 0 (for no buffer at all). This will prevent the slow consumer from buffering
+ any messages on the client side. Messages will remain on the server side ready
+ to be consumed by other consumers.
+ Setting this to 0 can give deterministic distribution between multiple
+ consumers on a queue.
+
+
+
+ Most of the consumers cannot be clearly identified as fast or slow consumers but are
+ in-between. In that case, setting the value of consumer-window-size
+ to optimize performance depends on the messaging use case and requires benchmarks to
+ find the optimal value, but a value of 1MiB is fine in most cases.
+
+ Using Core API
+ If HornetQ Core API is used, the consumer window size is specified by ServerLocator.setConsumerWindowSize() method and some of the
+ ClientSession.createConsumer() methods.
+
+
+ Using JMS
+ if JNDI is used to look up the connection factory, the consumer window size is
+ configured in hornetq-jms.xml:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty-connector"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+
+ <!-- Set the consumer window size to 0 to have *no* buffer on the client side -->
+ <consumer-window-size>0</consumer-window-size>
+</connection-factory>
+ If the connection factory is directly instantiated, the consumer window size is
+ specified by HornetQConnectionFactory.setConsumerWindowSize()
+ method.
+ Please see for an example which
+ shows how to configure HornetQ to prevent consumer buffering when dealing with slow
+ consumers.
+
+
+
+ Rate limited flow control
+ It is also possible to control the rate at which a consumer can
+ consume messages. This is a form of throttling and can be used to make sure that a
+ consumer never consumes messages at a rate faster than the rate specified.
+ The rate must be a positive integer to enable this functionality and is the maximum
+ desired message consumption rate specified in units of messages per second. Setting this
+ to -1 disables rate limited flow control. The default value is
+ -1.
+ Please see for a working example of
+ limiting consumer rate.
+
+ Using Core API
+ If the HornetQ core API is being used the rate can be set via the ServerLocator.setConsumerMaxRate(int consumerMaxRate) method or
+ alternatively via some of the ClientSession.createConsumer()
+ methods.
+
+
+ Using JMS
+ If JNDI is used to look up the connection factory, the max rate can be configured
+ in hornetq-jms.xml:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty-connector"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ <!-- We limit consumers created on this connection factory to consume messages at a maximum rate
+ of 10 messages per sec -->
+ <consumer-max-rate>10</consumer-max-rate>
+</connection-factory>
+ If the connection factory is directly instantiated, the max rate size can be set
+ via the HornetQConnectionFactory.setConsumerMaxRate(int
+ consumerMaxRate) method.
+
+ Rate limited flow control can be used in conjunction with window based flow
+ control. Rate limited flow control only effects how many messages a client can
+ consume in a second and not how many messages are in its buffer. So if you had a
+ slow rate limit and a high window based limit the clients internal buffer would
+ soon fill up with messages.
+
+ Please see for an example which
+ shows how to configure HornetQ to prevent consumer buffering when dealing with slow
+ consumers.
+
+
+
+
+ Producer flow control
+ HornetQ also can limit the amount of data sent from a client to a server to prevent the
+ server being overwhelmed.
+
+ Window based flow control
+ In a similar way to consumer window based flow control, HornetQ producers, by
+ default, can only send messages to an address as long as they have sufficient credits to
+ do so. The amount of credits required to send a message is given by the size of the
+ message.
+ As producers run low on credits they request more from the server, when the server
+ sends them more credits they can send more messages.
+ The amount of credits a producer requests in one go is known as the window size.
+ The window size therefore determines the amount of bytes that can be in-flight at any
+ one time before more need to be requested - this prevents the remoting connection from
+ getting overloaded.
+
+ Using Core API
+ If the HornetQ core API is being used, window size can be set via the ServerLocator.setProducerWindowSize(int producerWindowSize)
+ method.
+
+
+ Using JMS
+ If JNDI is used to look up the connection factory, the producer window size can be
+ configured in hornetq-jms.xml:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty-connector"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ <producer-window-size>10</producer-window-size>
+</connection-factory>
+ If the connection factory is directly instantiated, the producer window size can
+ be set via the HornetQConnectionFactory.setProducerWindowSize(int
+ producerWindowSize) method.
+
+
+ Blocking producer window based flow control
+ Normally the server will always give the same number of credits as have been
+ requested. However, it is also possible to set a maximum size on any address, and the
+ server will never send more credits than could cause the address's upper memory limit
+ to be exceeded.
+ For example, if I have a JMS queue called "myqueue", I could set the maximum
+ memory size to 10MiB, and the the server will control the number of credits sent to
+ any producers which are sending any messages to myqueue such that the total messages
+ in the queue never exceeds 10MiB.
+ When the address gets full, producers will block on the client side until more
+ space frees up on the address, i.e. until messages are consumed from the queue thus
+ freeing up space for more messages to be sent.
+ We call this blocking producer flow control, and it's an efficient way to prevent
+ the server running out of memory due to producers sending more messages than can be
+ handled at any time.
+ It is an alternative approach to paging, which does not block producers but
+ instead pages messages to storage.
+ To configure an address with a maximum size and tell the server that you want to
+ block producers for this address if it becomes full, you need to define an
+ AddressSettings () block for the
+ address and specify max-size-bytes and address-full-policy
+ The address block applies to all queues registered to that address. I.e. the total
+ memory for all queues bound to that address will not exceed max-size-bytes. In the case of JMS topics this means the total memory of all subscriptions in the topic won't
+ exceed max-size-bytes.
+ Here's an example:
+
+<address-settings>
+ <address-setting match="jms.queue.exampleQueue">
+ <max-size-bytes>100000</max-size-bytes>
+ <address-full-policy>BLOCK</address-full-policy>
+ </address-setting>
+</address-settings>
+ The above example would set the max size of the JMS queue "exampleQueue" to be
+ 100000 bytes and would block any producers sending to that address to prevent that
+ max size being exceeded.
+ Note the policy must be set to BLOCK to enable blocking producer
+ flow control.
+ Note that in the default configuration all addresses are set to block producers after 10 MiB of message data
+ is in the address. This means you cannot send more than 10MiB of message data to an address without it being consumed before the producers
+ will be blocked. If you do not want this behaviour increase the max-size-bytes parameter or change the
+ address full message policy.
+
+
+
+
+ Rate limited flow control
+ HornetQ also allows the rate a producer can emit message to be limited, in units of
+ messages per second. By specifying such a rate, HornetQ will ensure that producer never
+ produces messages at a rate higher than that specified.
+ The rate must be a positive integer to enable this functionality and is the maximum
+ desired message consumption rate specified in units of messages per second. Setting this
+ to -1 disables rate limited flow control. The default value is
+ -1.
+ Please see the for a working example
+ of limiting producer rate.
+
+ Using Core API
+ If the HornetQ core API is being used the rate can be set via the ServerLocator.setProducerMaxRate(int consumerMaxRate) method or
+ alternatively via some of the ClientSession.createProducer()
+ methods.
+
+
+ Using JMS
+ If JNDI is used to look up the connection factory, the max rate can be configured
+ in hornetq-jms.xml:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty-connector"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ <!-- We limit producers created on this connection factory to produce messages at a maximum rate
+ of 10 messages per sec -->
+ <producer-max-rate>10</producer-max-rate>
+</connection-factory>
+ If the connection factory is directly instantiated, the max rate size can be set
+ via the HornetQConnectionFactory.setProducerMaxRate(int
+ consumerMaxRate) method.
+
+
+
+
diff --git a/docs/user-manual/en/ha.xml b/docs/user-manual/en/ha.xml
new file mode 100644
index 0000000000..f4b2d2bed5
--- /dev/null
+++ b/docs/user-manual/en/ha.xml
@@ -0,0 +1,539 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ High Availability and Failover
+
+ We define high availability as the ability for the system to continue
+ functioning after failure of one or more of the servers.
+
+ A part of high availability is failover which we define as the
+ ability for client connections to migrate from one server to another in event of
+ server failure so client applications can continue to operate.
+
+
+ Live - Backup Groups
+
+ HornetQ allows servers to be linked together as live - backup
+ groups where each live server can have 1 or more backup servers. A backup server is owned by
+ only one live server. Backup servers are not operational until failover occurs, however 1
+ chosen backup, which will be in passive mode, announces its status and waits to take over
+ the live servers work
+
+ Before failover, only the live server is serving the HornetQ clients while the backup
+ servers remain passive or awaiting to become a backup server. When a live server crashes or
+ is brought down in the correct mode, the backup server currently in passive mode will become
+ live and another backup server will become passive. If a live server restarts after a
+ failover then it will have priority and be the next server to become live when the current
+ live server goes down, if the current live server is configured to allow automatic failback
+ then it will detect the live server coming back up and automatically stop.
+
+
+ HA modes
+ HornetQ supports two different strategies for backing up a server shared
+ store and replication.
+
+ Only persistent message data will survive failover. Any non persistent message
+ data will not be available after failover.
+
+
+
+
+ Data Replication
+ Support for network-based data replication was added in version 2.3.
+ When using replication, the live and the backup servers do not share the same
+ data directories, all data synchronization is done over the network. Therefore all (persistent)
+ data received by the live server will be duplicated to the backup.
+
+ Notice that upon start-up the backup server will first need to synchronize all
+ existing data from the live server before becoming capable of replacing the live
+ server should it fail. So unlike when using shared storage, a replicating backup will
+ not be a fully operational backup right after start-up, but only after it finishes
+ synchronizing the data with its live server. The time it will take for this to happen
+ will depend on the amount of data to be synchronized and the connection speed.
+
+
+ Synchronization occurs in parallel with current network traffic so this won't cause any
+ blocking on current clients.
+
+ Replication will create a copy of the data at the backup. One issue to be aware
+ of is: in case of a successful fail-over, the backup's data will be newer than
+ the one at the live's storage. If you configure your live server to perform a
+ 'fail-back' when restarted, it will synchronize
+ its data with the backup's. If both servers are shutdown, the administrator will have
+ to determine which one has the lastest data.
+
+ The replicating live and backup pair must be part of a cluster. The Cluster
+ Connection also defines how backup servers will find the remote live servers to pair
+ with. Refer to for details on how this is done, and how
+ to configure a cluster connection. Notice that:
+
+
+
+ Both live and backup servers must be part of the same cluster. Notice
+ that even a simple live/backup replicating pair will require a cluster configuration.
+
+
+ Their cluster user and password must match.
+
+
+
+ Within a cluster, there are two ways that a backup server will locate a live server to replicate
+ from, these are:
+
+
+
+ specifying a node group. You can specify a group of live servers that a backup
+ server can connect to. This is done by configuring backup-group-name in the main
+ hornetq-configuration.xml. A Backup server will only connect to a live server that
+ shares the same node group name
+
+
+ connecting to any live. Simply put not configuring backup-group-name
+ will allow a backup server to connect to any live server
+
+
+
+ A backup-group-name example: suppose you have 5 live servers and 6 backup
+ servers:
+
+
+ live1, live2, live3: with
+ backup-group-name=fish
+
+
+ live4, live5: with backup-group-name=bird
+
+
+ backup1, backup2, backup3,
+ backup4: with backup-group-name=fish
+
+
+ backup5, backup6: with
+ backup-group-name=bird
+
+
+ After joining the cluster the backups with backup-group-name=fish will
+ search for live servers with backup-group-name=fish to pair with. Since there
+ is one backup too many, the fish will remain with one spare backup.
+ The 2 backups with backup-group-name=bird (backup5 and
+ backup6) will pair with live servers live4 and
+ live5.
+
+ The backup will search for any live server that it is configured to connect to. It then tries to
+ replicate with each live server in turn until it finds a live server that has no current backup
+ configured. If no live server is available it will wait until the cluster topology changes and
+ repeats the process.
+
+ This is an important distinction from a shared-store backup, as in that case if
+ the backup starts and does not find its live server, the server will just activate
+ and start to serve client requests. In the replication case, the backup just keeps
+ waiting for a live server to pair with. Notice that in replication the backup server
+ does not know whether any data it might have is up to date, so it really cannot
+ decide to activate automatically. To activate a replicating backup server using the data
+ it has, the administrator must change its configuration to make a live server of it,
+ that change backup=true to backup=false.
+
+
+ Much like in the shared-store case, when the live server stops or crashes,
+ its replicating backup will become active and take over its duties. Specifically,
+ the backup will become active when it loses connection to its live server. This can
+ be problematic because this can also happen because of a temporary network
+ problem. In order to address this issue, the backup will try to determine whether it
+ still can connect to the other servers in the cluster. If it can connect to more
+ than half the servers, it will become active, if more than half the servers also
+ disappeared with the live, the backup will wait and try reconnecting with the live.
+ This avoids a split brain situation.
+
+
+ Configuration
+
+ To configure the live and backup servers to be a replicating pair, configure
+ both servers' hornetq-configuration.xml to have:
+
+
+<!-- FOR BOTH LIVE AND BACKUP SERVERS' -->
+<shared-store>false</shared-store>
+.
+.
+<cluster-connections>
+ <cluster-connection name="my-cluster">
+ ...
+ </cluster-connection>
+</cluster-connections>
+
+
+ The backup server must also be configured as a backup.
+
+
+<backup>true</backup>
+
+
+
+
+
+ Shared Store
+ When using a shared store, both live and backup servers share the
+ same entire data directory using a shared file system.
+ This means the paging directory, journal directory, large messages and binding
+ journal.
+ When failover occurs and a backup server takes over, it will load the
+ persistent storage from the shared file system and clients can connect to
+ it.
+ This style of high availability differs from data replication in that it
+ requires a shared file system which is accessible by both the live and backup
+ nodes. Typically this will be some kind of high performance Storage Area Network
+ (SAN). We do not recommend you use Network Attached Storage (NAS), e.g. NFS
+ mounts to store any shared journal (NFS is slow).
+ The advantage of shared-store high availability is that no replication occurs
+ between the live and backup nodes, this means it does not suffer any performance
+ penalties due to the overhead of replication during normal operation.
+ The disadvantage of shared store replication is that it requires a shared file
+ system, and when the backup server activates it needs to load the journal from
+ the shared store which can take some time depending on the amount of data in the
+ store.
+ If you require the highest performance during normal operation, have access to
+ a fast SAN, and can live with a slightly slower failover (depending on amount of
+ data), we recommend shared store high availability
+
+
+
+ Configuration
+ To configure the live and backup servers to share their store, configure
+ all hornetq-configuration.xml:
+
+<shared-store>true</shared-store>
+
+ Additionally, each backup server must be flagged explicitly as a backup:
+
+<backup>true</backup>
+ In order for live - backup groups to operate properly with a shared store,
+ both servers must have configured the location of journal directory to point
+ to the same shared location (as explained in
+ )
+
+ todo write something about GFS
+
+ Also each node, live and backups, will need to have a cluster connection defined even if not
+ part of a cluster. The Cluster Connection info defines how backup servers announce there presence
+ to its live server or any other nodes in the cluster. Refer to for details
+ on how this is done.
+
+
+
+ Failing Back to live Server
+ After a live server has failed and a backup taken has taken over its duties, you may want to
+ restart the live server and have clients fail back.
+ In case of "shared disk", simply restart the original live
+ server and kill the new live server. You can do this by killing the process itself or just waiting for the server to crash naturally.
+ In case of a replicating live server that has been replaced by a remote backup you will need to also set check-for-live-server. This option is necessary because a starting server cannot know whether there is a (remote) server running in its place, so with this option set, the server will check the cluster for another server using its node-ID and if it finds one it will try initiate a fail-back. This option only applies to live servers that are restarting, it is ignored by backup servers.
+ It is also possible to cause failover to occur on normal server shutdown, to enable
+ this set the following property to true in the hornetq-configuration.xml
+ configuration file like so:
+
+<failover-on-shutdown>true</failover-on-shutdown>
+ By default this is set to false, if by some chance you have set this to false but still
+ want to stop the server normally and cause failover then you can do this by using the management
+ API as explained at
+ You can also force the running live server to shutdown when the old live server comes back up allowing
+ the original live server to take over automatically by setting the following property in the
+ hornetq-configuration.xml configuration file as follows:
+
+<allow-failback>true</allow-failback>
+ In replication HA mode you need to set an extra property check-for-live-server
+ to true. If set to true, during start-up a live server will first search the cluster for another server using its nodeID. If it finds one, it will contact this server and try to "fail-back". Since this is a remote replication scenario, the "starting live" will have to synchronize its data with the server running with its ID, once they are in sync, it will request the other server (which it assumes it is a back that has assumed its duties) to shutdown for it to take over. This is necessary because otherwise the live server has no means to know whether there was a fail-over or not, and if there was if the server that took its duties is still running or not. To configure this option at your hornetq-configuration.xml configuration file as follows:
+
+<check-for-live-server>true</check-for-live-server>
+
+
+ Colocated Backup Servers
+ It is also possible when running standalone to colocate backup servers in the same
+ JVM as another live server.The colocated backup will become a backup for another live
+ server in the cluster but not the one it shares the vm with. To configure a colocated
+ backup server simply add the following to the hornetq-configuration.xml file
+
+<backup-servers>
+ <backup-server name="backup2" inherit-configuration="true" port-offset="1000">
+ <configuration>
+ <bindings-directory>target/server1/data/messaging/bindings</bindings-directory>
+ <journal-directory>target/server1/data/messaging/journal</journal-directory>
+ <large-messages-directory>target/server1/data/messaging/largemessages</large-messages-directory>
+ <paging-directory>target/server1/data/messaging/paging</paging-directory>
+ </configuration>
+ </backup-server>
+</backup-servers>
+
+ you will notice 3 attributes on the backup-server, name
+ which is a unique name used to identify the backup server, inherit-configuration
+ which if set to true means the server will inherit the configuration of its parent server
+ and port-offset which is what the port for any netty connectors or
+ acceptors will be increased by if the configuration is inherited.
+ it is also possible to configure the backup server in the normal way, in this example you will
+ notice we have changed the journal directories.
+
+
+
+ Failover Modes
+ HornetQ defines two types of client failover:
+
+
+ Automatic client failover
+
+
+ Application-level client failover
+
+
+ HornetQ also provides 100% transparent automatic reattachment of connections to the
+ same server (e.g. in case of transient network problems). This is similar to failover,
+ except it is reconnecting to the same server and is discussed in
+
+ During failover, if the client has consumers on any non persistent or temporary
+ queues, those queues will be automatically recreated during failover on the backup node,
+ since the backup node will not have any knowledge of non persistent queues.
+
+ Automatic Client Failover
+ HornetQ clients can be configured to receive knowledge of all live and backup servers, so
+ that in event of connection failure at the client - live server connection, the
+ client will detect this and reconnect to the backup server. The backup server will
+ then automatically recreate any sessions and consumers that existed on each
+ connection before failover, thus saving the user from having to hand-code manual
+ reconnection logic.
+ HornetQ clients detect connection failure when it has not received packets from
+ the server within the time given by client-failure-check-period
+ as explained in section . If the client does not
+ receive data in good time, it will assume the connection has failed and attempt
+ failover. Also if the socket is closed by the OS, usually if the server process is
+ killed rather than the machine itself crashing, then the client will failover straight away.
+
+ HornetQ clients can be configured to discover the list of live-backup server groups in a
+ number of different ways. They can be configured explicitly or probably the most
+ common way of doing this is to use server discovery for the
+ client to automatically discover the list. For full details on how to configure
+ server discovery, please see .
+ Alternatively, the clients can explicitly connect to a specific server and download
+ the current servers and backups see .
+ To enable automatic client failover, the client must be configured to allow
+ non-zero reconnection attempts (as explained in ).
+ By default failover will only occur after at least one connection has been made to
+ the live server. In other words, by default, failover will not occur if the client
+ fails to make an initial connection to the live server - in this case it will simply
+ retry connecting to the live server according to the reconnect-attempts property and
+ fail after this number of attempts.
+
+ Failing over on the Initial Connection
+
+ Since the client does not learn about the full topology until after the first
+ connection is made there is a window where it does not know about the backup. If a failure happens at
+ this point the client can only try reconnecting to the original live server. To configure
+ how many attempts the client will make you can set the property initialConnectAttempts
+ on the ClientSessionFactoryImpl or HornetQConnectionFactory or
+ initial-connect-attempts in xml. The default for this is 0, that
+ is try only once. Once the number of attempts has been made an exception will be thrown.
+
+
+ For examples of automatic failover with transacted and non-transacted JMS
+ sessions, please see and .
+
+ A Note on Server Replication
+ HornetQ does not replicate full server state between live and backup servers.
+ When the new session is automatically recreated on the backup it won't have any
+ knowledge of messages already sent or acknowledged in that session. Any
+ in-flight sends or acknowledgements at the time of failover might also be
+ lost.
+ By replicating full server state, theoretically we could provide a 100%
+ transparent seamless failover, which would avoid any lost messages or
+ acknowledgements, however this comes at a great cost: replicating the full
+ server state (including the queues, session, etc.). This would require
+ replication of the entire server state machine; every operation on the live
+ server would have to replicated on the replica server(s) in the exact same
+ global order to ensure a consistent replica state. This is extremely hard to do
+ in a performant and scalable way, especially when one considers that multiple
+ threads are changing the live server state concurrently.
+ It is possible to provide full state machine replication using techniques such
+ as virtual synchrony, but this does not scale
+ well and effectively serializes all operations to a single thread, dramatically
+ reducing concurrency.
+ Other techniques for multi-threaded active replication exist such as
+ replicating lock states or replicating thread scheduling but this is very hard
+ to achieve at a Java level.
+ Consequently it has decided it was not worth massively reducing performance
+ and concurrency for the sake of 100% transparent failover. Even without 100%
+ transparent failover, it is simple to guarantee once and
+ only once delivery, even in the case of failure, by using a
+ combination of duplicate detection and retrying of transactions. However this is
+ not 100% transparent to the client code.
+
+
+ Handling Blocking Calls During Failover
+ If the client code is in a blocking call to the server, waiting for a response
+ to continue its execution, when failover occurs, the new session will not have
+ any knowledge of the call that was in progress. This call might otherwise hang
+ for ever, waiting for a response that will never come.
+ To prevent this, HornetQ will unblock any blocking calls that were in progress
+ at the time of failover by making them throw a javax.jms.JMSException (if using JMS), or a HornetQException with error code HornetQException.UNBLOCKED. It is up to the client code to catch
+ this exception and retry any operations if desired.
+ If the method being unblocked is a call to commit(), or prepare(), then the
+ transaction will be automatically rolled back and HornetQ will throw a javax.jms.TransactionRolledBackException (if using JMS), or a
+ HornetQException with error code HornetQException.TRANSACTION_ROLLED_BACK if using the core
+ API.
+
+
+ Handling Failover With Transactions
+ If the session is transactional and messages have already been sent or
+ acknowledged in the current transaction, then the server cannot be sure that
+ messages sent or acknowledgements have not been lost during the failover.
+ Consequently the transaction will be marked as rollback-only, and any
+ subsequent attempt to commit it will throw a javax.jms.TransactionRolledBackException (if using JMS), or a
+ HornetQException with error code HornetQException.TRANSACTION_ROLLED_BACK if using the core
+ API.
+
+ 2 phase commit
+
+ The caveat to this rule is when XA is used either via JMS or through the core API.
+ If 2 phase commit is used and prepare has already been called then rolling back could
+ cause a HeuristicMixedException. Because of this the commit will throw
+ a XAException.XA_RETRY exception. This informs the Transaction Manager
+ that it should retry the commit at some later point in time, a side effect of this is
+ that any non persistent messages will be lost. To avoid this use persistent
+ messages when using XA. With acknowledgements this is not an issue since they are
+ flushed to the server before prepare gets called.
+
+
+ It is up to the user to catch the exception, and perform any client side local
+ rollback code as necessary. There is no need to manually rollback the session -
+ it is already rolled back. The user can then just retry the transactional
+ operations again on the same session.
+ HornetQ ships with a fully functioning example demonstrating how to do this,
+ please see
+ If failover occurs when a commit call is being executed, the server, as
+ previously described, will unblock the call to prevent a hang, since no response
+ will come back. In this case it is not easy for the client to determine whether
+ the transaction commit was actually processed on the live server before failure
+ occurred.
+
+
+ If XA is being used either via JMS or through the core API then an XAException.XA_RETRY
+ is thrown. This is to inform Transaction Managers that a retry should occur at some point. At
+ some later point in time the Transaction Manager will retry the commit. If the original
+ commit has not occurred then it will still exist and be committed, if it does not exist
+ then it is assumed to have been committed although the transaction manager may log a warning.
+
+
+ To remedy this, the client can simply enable duplicate detection () in the transaction, and retry the
+ transaction operations again after the call is unblocked. If the transaction had
+ indeed been committed on the live server successfully before failover, then when
+ the transaction is retried, duplicate detection will ensure that any durable
+ messages resent in the transaction will be ignored on the server to prevent them
+ getting sent more than once.
+
+ By catching the rollback exceptions and retrying, catching unblocked calls
+ and enabling duplicate detection, once and only once delivery guarantees for
+ messages can be provided in the case of failure, guaranteeing 100% no loss
+ or duplication of messages.
+
+
+
+ Handling Failover With Non Transactional Sessions
+ If the session is non transactional, messages or acknowledgements can be lost
+ in the event of failover.
+ If you wish to provide once and only once
+ delivery guarantees for non transacted sessions too, enabled duplicate
+ detection, and catch unblock exceptions as described in
+
+
+
+ Getting Notified of Connection Failure
+ JMS provides a standard mechanism for getting notified asynchronously of
+ connection failure: java.jms.ExceptionListener. Please consult
+ the JMS javadoc or any good JMS tutorial for more information on how to use
+ this.
+ The HornetQ core API also provides a similar feature in the form of the class
+ org.hornet.core.client.SessionFailureListener
+ Any ExceptionListener or SessionFailureListener instance will always be called by
+ HornetQ on event of connection failure, irrespective of whether the connection was successfully failed over,
+ reconnected or reattached, however you can find out if reconnect or reattach has happened
+ by either the failedOver flag passed in on the connectionFailed
+ on SessionfailureListener or by inspecting the error code on the
+ javax.jms.JMSException which will be one of the following:
+
+ JMSException error codes
+
+
+
+
+
+ error code
+ Description
+
+
+
+
+ FAILOVER
+
+ Failover has occurred and we have successfully reattached or reconnected.
+
+
+
+ DISCONNECT
+
+ No failover has occurred and we are disconnected.
+
+
+
+
+
+
+
+ Application-Level Failover
+ In some cases you may not want automatic client failover, and prefer to handle any
+ connection failure yourself, and code your own manually reconnection logic in your
+ own failure handler. We define this as application-level
+ failover, since the failover is handled at the user application level.
+ To implement application-level failover, if you're using JMS then you need to set
+ an ExceptionListener class on the JMS connection. The
+ ExceptionListener will be called by HornetQ in the event that
+ connection failure is detected. In your ExceptionListener, you
+ would close your old JMS connections, potentially look up new connection factory
+ instances from JNDI and creating new connections. In this case you may well be using
+ HA-JNDI
+ to ensure that the new connection factory is looked up from a different server.
+ For a working example of application-level failover, please see
+ .
+ If you are using the core API, then the procedure is very similar: you would set a
+ FailureListener on the core ClientSession
+ instances.
+
+
+
diff --git a/docs/user-manual/en/images/architecture1.jpg b/docs/user-manual/en/images/architecture1.jpg
new file mode 100644
index 0000000000..cb1161f645
Binary files /dev/null and b/docs/user-manual/en/images/architecture1.jpg differ
diff --git a/docs/user-manual/en/images/architecture2.jpg b/docs/user-manual/en/images/architecture2.jpg
new file mode 100644
index 0000000000..274f578a5e
Binary files /dev/null and b/docs/user-manual/en/images/architecture2.jpg differ
diff --git a/docs/user-manual/en/images/architecture3.jpg b/docs/user-manual/en/images/architecture3.jpg
new file mode 100644
index 0000000000..3c1dfd5742
Binary files /dev/null and b/docs/user-manual/en/images/architecture3.jpg differ
diff --git a/docs/user-manual/en/images/console1.png b/docs/user-manual/en/images/console1.png
new file mode 100644
index 0000000000..19b6cbd835
Binary files /dev/null and b/docs/user-manual/en/images/console1.png differ
diff --git a/docs/user-manual/en/images/ha-replicated-store.png b/docs/user-manual/en/images/ha-replicated-store.png
new file mode 100644
index 0000000000..9065dfee67
Binary files /dev/null and b/docs/user-manual/en/images/ha-replicated-store.png differ
diff --git a/docs/user-manual/en/images/ha-shared-store.png b/docs/user-manual/en/images/ha-shared-store.png
new file mode 100644
index 0000000000..0be2766553
Binary files /dev/null and b/docs/user-manual/en/images/ha-shared-store.png differ
diff --git a/docs/user-manual/en/images/hornetQ-banner_final.png b/docs/user-manual/en/images/hornetQ-banner_final.png
new file mode 100644
index 0000000000..6388dff1f5
Binary files /dev/null and b/docs/user-manual/en/images/hornetQ-banner_final.png differ
diff --git a/docs/user-manual/en/images/hornetQ_logo_600px.png b/docs/user-manual/en/images/hornetQ_logo_600px.png
new file mode 100644
index 0000000000..b71f4ba130
Binary files /dev/null and b/docs/user-manual/en/images/hornetQ_logo_600px.png differ
diff --git a/docs/user-manual/en/intercepting-operations.xml b/docs/user-manual/en/intercepting-operations.xml
new file mode 100644
index 0000000000..60db27417c
--- /dev/null
+++ b/docs/user-manual/en/intercepting-operations.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+
+ Intercepting Operations
+ HornetQ supports interceptors to intercept packets entering
+ and exiting the server. Incoming and outgoing interceptors are be called for any packet
+ entering or exiting the server respectively. This allows custom code to be executed,
+ e.g. for auditing packets, filtering or other reasons. Interceptors can change the
+ packets they intercept. This makes interceptors powerful, but also potentially
+ dangerous.
+
+ Implementing The Interceptors
+ An interceptor must implement the Interceptor interface:
+
+package org.hornetq.api.core.interceptor;
+
+public interface Interceptor
+{
+ boolean intercept(Packet packet, RemotingConnection connection) throws HornetQException;
+}
+ The returned boolean value is important:
+
+
+ if true is returned, the process continues normally
+
+
+ if false is returned, the process is aborted, no other interceptors
+ will be called and the packet will not be processed further by the server.
+
+
+
+
+ Configuring The Interceptors
+ Both incoming and outgoing interceptors are configured in
+ hornetq-configuration.xml:
+
+<remoting-incoming-interceptors>
+ <class-name>org.hornetq.jms.example.LoginInterceptor</class-name>
+ <class-name>org.hornetq.jms.example.AdditionalPropertyInterceptor</class-name>
+</remoting-incoming-interceptors>
+
+<remoting-outgoing-interceptors>
+ <class-name>org.hornetq.jms.example.LogoutInterceptor</class-name>
+ <class-name>org.hornetq.jms.example.AdditionalPropertyInterceptor</class-name>
+</remoting-outgoing-interceptors>
+ The interceptors classes (and their dependencies) must be added to the server classpath
+ to be properly instantiated and called.
+
+
+ Interceptors on the Client Side
+ The interceptors can also be run on the client side to intercept packets either sent by the
+ client to the server or by the server to the client. This is done by adding the interceptor to
+ the ServerLocator with the addIncomingInterceptor(Interceptor) or
+ addOutgoingInterceptor(Interceptor) methods.
+ As noted above, if an interceptor returns false then the sending of the
+ packet is aborted which means that no other interceptors are be called and the packet is not
+ be processed further by the client. Typically this process happens transparently to the client
+ (i.e. it has no idea if a packet was aborted or not). However, in the case of an outgoing packet
+ that is sent in a blocking fashion a HornetQException will
+ be thrown to the caller. The exception is thrown because blocking sends provide reliability and
+ it is considered an error for them not to succeed. Blocking sends occurs when,
+ for example, an application invokes setBlockOnNonDurableSend(true) or
+ setBlockOnDurableSend(true) on its ServerLocator or if an
+ application is using a JMS connection factory retrieved from JNDI that has either
+ block-on-durable-send or block-on-non-durable-send
+ set to true. Blocking is also used for packets dealing with transactions (e.g.
+ commit, roll-back, etc.). The HornetQException thrown will contain the name
+ of the interceptor that returned false.
+ As on the server, the client interceptor classes (and their dependencies) must be added to the classpath
+ to be properly instantiated and invoked.
+
+
+ Example
+ See for an example which
+ shows how to use interceptors to add properties to a message on the server.
+
+
diff --git a/docs/user-manual/en/interoperability.xml b/docs/user-manual/en/interoperability.xml
new file mode 100644
index 0000000000..e4261d70b7
--- /dev/null
+++ b/docs/user-manual/en/interoperability.xml
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Interoperability
+
+ Stomp
+ Stomp is a text-orientated wire protocol that allows
+ Stomp clients to communicate with Stomp Brokers. HornetQ now supports Stomp 1.0, 1.1 and 1.2.
+ Stomp clients are available for
+ several languages and platforms making it a good choice for interoperability.
+
+ Native Stomp support
+ HornetQ provides native support for Stomp. To be able to send and receive Stomp messages,
+ you must configure a NettyAcceptor with a protocols
+ parameter set to have stomp:
+
+<acceptor name="stomp-acceptor">
+ <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
+ <param key="protocols" value="STOMP"/>
+ <param key="port" value="61613"/>
+</acceptor>
+ With this configuration, HornetQ will accept Stomp connections on
+ the port 61613 (which is the default port of the Stomp brokers).
+ See the stomp example which shows how to configure a HornetQ server with Stomp.
+
+ Limitations
+ Message acknowledgements are not transactional. The ACK frame can not be part of a transaction
+ (it will be ignored if its transaction header is set).
+
+
+ Stomp 1.1/1.2 Notes
+
+ Virtual Hosting
+ HornetQ currently doesn't support virtual hosting, which means the 'host' header
+ in CONNECT fram will be ignored.
+
+
+ Heart-beating
+ HornetQ 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.
+
+
+
+
+
+ Mapping Stomp destinations to HornetQ addresses and queues
+ Stomp clients deals with destinations 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.
+ In HornetQ, these destinations are mapped to addresses and queues.
+ When a Stomp client sends a message (using a SEND frame), the specified destination is mapped
+ to an address.
+ When a Stomp client subscribes (or unsubscribes) for a destination (using a SUBSCRIBE
+ or UNSUBSCRIBE frame), the destination is mapped to a HornetQ queue.
+
+
+ STOMP and connection-ttl
+ 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 connection-ttl for more information. This value can be overridden using connection-ttl-override.
+
+ 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:
+
+
+<acceptor name="stomp-acceptor">
+ <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
+ <param key="protocols" value="STOMP"/>
+ <param key="port" value="61613"/>
+ <param key="connection-ttl" value="20000"/>
+</acceptor>
+ 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.
+
+ 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 Stomp 1.1 users can use heart-beats to maintain the life cycle of stomp
+ connections.
+
+
+
+ Stomp and JMS interoperability
+
+ Using JMS destinations
+ As explained in , JMS destinations are also mapped to HornetQ addresses and queues.
+ If you want to use Stomp to send messages to JMS destinations, the Stomp destinations must follow the same convention:
+
+
+ send or subscribe to a JMS Queue by prepending the queue name by jms.queue..
+ For example, to send a message to the orders JMS Queue, the Stomp client must send the frame:
+
+SEND
+destination:jms.queue.orders
+
+hello queue orders
+^@
+
+
+ send or subscribe to a JMS Topic by prepending the topic name by jms.topic..
+ For example to subscribe to the stocks JMS Topic, the Stomp client must send the frame:
+
+SUBSCRIBE
+destination:jms.topic.stocks
+
+^@
+
+
+
+
+
+ Sending and consuming Stomp message from JMS or HornetQ Core API
+ Stomp is mainly a text-orientated protocol. To make it simpler to interoperate with JMS and HornetQ Core API,
+ our Stomp implementation checks for presence of the content-length header to decide how to map a Stomp message
+ to a JMS Message or a Core message.
+
+ If the Stomp message does not have a content-length header, it will be mapped to a JMS TextMessage
+ or a Core message with a single nullable SimpleString in the body buffer.
+ Alternatively, if the Stomp message has a content-length header,
+ it will be mapped to a JMS BytesMessage
+ or a Core message with a byte[] in the body buffer.
+ The same logic applies when mapping a JMS message or a Core message to Stomp. A Stomp client can check the presence
+ of the content-length header to determine the type of the message body (String or bytes).
+
+
+ Message IDs for Stomp messages
+ 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. HornetQ 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 stomp-enable-message-id to true. For example:
+
+<acceptor name="stomp-acceptor">
+ <factory-class>org.hornetq.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>
+ 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
+ hq-message-id and the value is a String representation of a long type internal
+ message id prefixed with "STOMP", like:
+
+hq-message-id : STOMP12345
+ If stomp-enable-message-id is not specified in the configuration, default
+ is false.
+
+
+ Handling of Large Messages with Stomp
+ Stomp clients may send very large bodys of frames which can exceed the size of HornetQ
+ server's internal buffer, causing unexpected errors. To prevent this situation from happening,
+ HornetQ provides a stomp configuration attribute stomp-min-large-message-size.
+ This attribute can be configured inside a stomp acceptor, as a parameter. For example:
+
+ <acceptor name="stomp-acceptor">
+ <factory-class>org.hornetq.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>
+ The type of this attribute is integer. When this attributed is configured, HornetQ 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
+ stomp-min-large-message, 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.
+ If a large message is compressed, the server will uncompressed it before sending it to
+ stomp clients. The default value of stomp-min-large-message-size is the same
+ as the default value of min-large-message-size.
+
+
+
+
+ Stomp Over Web Sockets
+ HornetQ also support Stomp over Web Sockets. Modern web browser which support Web Sockets can send and receive
+ Stomp messages from HornetQ.
+ To enable Stomp over Web Sockets, you must configure a NettyAcceptor with a protocol
+ parameter set to stomp_ws:
+
+<acceptor name="stomp-ws-acceptor">
+ <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
+ <param key="protocols" value="STOMP_WS"/>
+ <param key="port" value="61614"/>
+</acceptor>
+ With this configuration, HornetQ will accept Stomp connections over Web Sockets on
+ the port 61614 with the URL path /stomp.
+ Web browser can then connect to ws://<server>:61614/stomp using a Web Socket to send and receive Stomp
+ messages.
+ A companion JavaScript library to ease client-side development is available from
+ GitHub (please see
+ its documentation for a complete description).
+ The stomp-websockets example shows how to configure HornetQ server to have web browsers and Java
+ applications exchanges messages on a JMS topic.
+
+
+
+ StompConnect
+ StompConnect 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 HornetQ into a Stomp Broker and
+ use any of the available stomp clients. These include clients written in C, C++, c# and
+ .net etc.
+ To run StompConnect first start the HornetQ server and make sure that it is using
+ JNDI.
+ Stomp requires the file jndi.properties to be available on the
+ classpath. This should look something like:
+
+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
+ Make sure this file is in the classpath along with the StompConnect jar and the
+ HornetQ jars and simply run java org.codehaus.stomp.jms.Main.
+
+
+
+
+ REST
+ Please see
+
+
+ AMQP
+ HornetQ supports the AMQP 1.0
+ specification. To enable AMQP you must configure a Netty Acceptor to receive AMQP clients, like so:
+
+<acceptor name="stomp-acceptor">
+<factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
+<param key="protocols" value="AMQP"/>
+<param key="port" value="5672"/>
+</acceptor>
+
+ HornetQ will then accept AMQP 1.0 clients on port 5672 which is the default AMQP port.
+ There are 2 Stomp examples available see proton-j and proton-ruby which use the qpid Java and Ruby clients
+ respectively
+
+ AMQP and security
+ The HornetQ 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 HornetQ security configuration.
+
+
+ AMQP Links
+ An AMQP Link is a uni directional transport for messages between a source and a target, i.e. a client and the
+ HornetQ 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 HornetQ Message and forwarded to its destination or target. A
+ Receiver will map onto a HornetQ Server Consumer and convert HornetQ messages back into AMQP messages before being delivered.
+
+
+ AMQP and destinations
+ 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
+ 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
+
+
+ AMQP and Coordinations - Handling Transactions
+ 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.
+ AMQP allows the use of multiple transactions per session, amqp:multi-txns-per-ssn,
+ however in this version HornetQ will only support single transactions per session
+
+
+
diff --git a/docs/user-manual/en/jms-bridge.xml b/docs/user-manual/en/jms-bridge.xml
new file mode 100644
index 0000000000..16bdfbf007
--- /dev/null
+++ b/docs/user-manual/en/jms-bridge.xml
@@ -0,0 +1,450 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ The JMS Bridge
+ HornetQ includes a fully functional JMS message bridge.
+ The function of the bridge is to consume messages from a source queue or topic, and
+ send them to a target queue or topic, typically on a different server.
+ 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, and where the connection may be unreliable.
+ A bridge can be deployed as a standalone application, with HornetQ standalone server or inside a JBoss AS
+ instance. The source and the target can be located in the same virtual machine or another one.
+ The bridge can also be used to bridge messages from other non HornetQ JMS servers, as
+ long as they are JMS 1.1 compliant.Do not confuse a JMS bridge with a core
+ bridge. A JMS bridge can be used to bridge any two JMS 1.1 compliant JMS
+ providers and uses the JMS API. A core bridge (described in ) is used to bridge any two HornetQ instances and
+ uses the core API. Always use a core bridge if you can in preference to a JMS
+ bridge. The core bridge will typically provide better performance than a JMS
+ bridge. Also the core bridge can provide once and only once
+ delivery guarantees without using XA.
+ The bridge has built-in resilience to failure so if the source or target server
+ connection is lost, e.g. due to network failure, the bridge will retry connecting to the
+ source and/or target until they come back online. When it comes back online it will
+ resume operation as normal.
+ The bridge can be configured with an optional JMS selector, so it will only consume
+ messages matching that JMS selector
+ It can be configured to consume from a queue or a topic. When it consumes from a topic
+ it can be configured to consume using a non durable or durable subscription
+ Typically, the bridge is deployed by the JBoss Micro Container via a beans configuration file.
+ This would typically be deployed inside the JBoss Application Server and the following
+ example shows an example of a beans file that bridges 2 destinations which are actually
+ on the same server.
+
+<?xml version="1.0" encoding="UTF-8"?>
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+ <bean name="JMSBridge" class="org.hornetq.api.jms.bridge.impl.JMSBridgeImpl">
+ <!-- HornetQ must be started before the bridge -->
+ <depends>HornetQServer</depends>
+ <constructor>
+ <!-- Source ConnectionFactory Factory -->
+ <parameter>
+ <inject bean="SourceCFF"/>
+ </parameter>
+ <!-- Target ConnectionFactory Factory -->
+ <parameter>
+ <inject bean="TargetCFF"/>
+ </parameter>
+ <!-- Source DestinationFactory -->
+ <parameter>
+ <inject bean="SourceDestinationFactory"/>
+ </parameter>
+ <!-- Target DestinationFactory -->
+ <parameter>
+ <inject bean="TargetDestinationFactory"/>
+ </parameter>
+ <!-- Source User Name (no username here) -->
+ <parameter><null /></parameter>
+ <!-- Source Password (no password here)-->
+ <parameter><null /></parameter>
+ <!-- Target User Name (no username here)-->
+ <parameter><null /></parameter>
+ <!-- Target Password (no password here)-->
+ <parameter><null /></parameter>
+ <!-- Selector -->
+ <parameter><null /></parameter>
+ <!-- Failure Retry Interval (in ms) -->
+ <parameter>5000</parameter>
+ <!-- Max Retries -->
+ <parameter>10</parameter>
+ <!-- Quality Of Service -->
+ <parameter>ONCE_AND_ONLY_ONCE</parameter>
+ <!-- Max Batch Size -->
+ <parameter>1</parameter>
+ <!-- Max Batch Time (-1 means infinite) -->
+ <parameter>-1</parameter>
+ <!-- Subscription name (no subscription name here)-->
+ <parameter><null /></parameter>
+ <!-- Client ID (no client ID here)-->
+ <parameter><null /></parameter>
+ <!-- Add MessageID In Header -->
+ <parameter>true</parameter>
+ <!-- register the JMS Bridge in the AS MBeanServer -->
+ <parameter>
+ <inject bean="MBeanServer"/>
+ </parameter>
+ <parameter>org.hornetq:service=JMSBridge</parameter>
+ </constructor>
+ <property name="transactionManager">
+ <inject bean="RealTransactionManager"/>
+ </property>
+ </bean>
+
+ <!-- SourceCFF describes the ConnectionFactory used to connect to the source destination -->
+ <bean name="SourceCFF"
+ class="org.hornetq.api.jms.bridge.impl.JNDIConnectionFactoryFactory">
+ <constructor>
+ <parameter>
+ <inject bean="JNDI" />
+ </parameter>
+ <parameter>/ConnectionFactory</parameter>
+ </constructor>
+ </bean>
+
+ <!-- TargetCFF describes the ConnectionFactory used to connect to the target destination -->
+ <bean name="TargetCFF"
+ class="org.hornetq.api.jms.bridge.impl.JNDIConnectionFactoryFactory">
+ <constructor>
+ <parameter>
+ <inject bean="JNDI" />
+ </parameter>
+ <parameter>/ConnectionFactory</parameter>
+ </constructor>
+ </bean>
+
+ <!-- SourceDestinationFactory describes the Destination used as the source -->
+ <bean name="SourceDestinationFactory" class="org.hornetq.api.jms.bridge.impl.JNDIDestinationFactory">
+ <constructor>
+ <parameter>
+ <inject bean="JNDI" />
+ </parameter>
+ <parameter>/queue/source</parameter>
+ </constructor>
+ </bean>
+
+ <!-- TargetDestinationFactory describes the Destination used as the target -->
+ <bean name="TargetDestinationFactory" class="org.hornetq.api.jms.bridge.impl.JNDIDestinationFactory">
+ <constructor>
+ <parameter>
+ <inject bean="JNDI" />
+ </parameter>
+ <parameter>/queue/target</parameter>
+ </constructor>
+ </bean>
+
+ <!-- JNDI is a Hashtable containing the JNDI properties required -->
+ <!-- to connect to the sources and targets JMS resrouces -->
+ <bean name="JNDI" class="java.util.Hashtable">
+ <constructor class="java.util.Map">
+ <map class="java.util.Hashtable" keyClass="String"
+ valueClass="String">
+ <entry>
+ <key>java.naming.factory.initial</key>
+ <value>org.jnp.interfaces.NamingContextFactory</value>
+ </entry>
+ <entry>
+ <key>java.naming.provider.url</key>
+ <value>jnp://localhost:1099</value>
+ </entry>
+ <entry>
+ <key>java.naming.factory.url.pkgs</key>
+ <value>org.jboss.naming:org.jnp.interfaces"</value>
+ </entry>
+ <entry>
+ <key>jnp.timeout</key>
+ <value>5000</value>
+ </entry>
+ <entry>
+ <key>jnp.sotimeout</key>
+ <value>5000</value>
+ </entry>
+ </map>
+ </constructor>
+ </bean>
+
+ <bean name="MBeanServer" class="javax.management.MBeanServer">
+ <constructor factoryClass="org.jboss.mx.util.MBeanServerLocator" factoryMethod="locateJBoss"/>
+ </bean>
+</deployment>
+
+ JMS Bridge Parameters
+ The main bean deployed is the JMSBridge bean. The bean is
+ configurable by the parameters passed to its constructor.
+
+ To let a parameter be unspecified (for example, if the authentication is
+ anonymous or no message selector is provided), use <null
+ /> for the unspecified parameter value.
+
+
+
+ Source Connection Factory Factory
+ This injects the SourceCFF bean (also defined in the
+ beans file). This bean is used to create the source
+ ConnectionFactory
+
+
+
+ Target Connection Factory Factory
+ This injects the TargetCFF bean (also defined in the
+ beans file). This bean is used to create the target
+ ConnectionFactory
+
+
+
+ Source Destination Factory Factory
+ This injects the SourceDestinationFactory bean (also
+ defined in the beans file). This bean is used to create the
+ source
+ Destination
+
+
+
+ Target Destination Factory Factory
+ This injects the TargetDestinationFactory bean (also
+ defined in the beans file). This bean is used to create the
+ target
+ Destination
+
+
+
+ Source User Name
+ this parameter is the username for creating the
+ source connection
+
+
+ Source Password
+ this parameter is the parameter for creating the
+ source connection
+
+
+ Target User Name
+ this parameter is the username for creating the
+ target connection
+
+
+ Target Password
+ this parameter is the password for creating the
+ target connection
+
+
+ Selector
+ This represents a JMS selector expression used for consuming messages from
+ the source destination. Only messages that match the selector expression
+ will be bridged from the source to the target destination
+ The selector expression must follow the JMS
+ selector syntax
+
+
+ Failure Retry Interval
+ This represents the amount of time in ms to wait between trying to
+ recreate connections to the source or target servers when the bridge has
+ detected they have failed
+
+
+ Max Retries
+ This represents the number of times to attempt to recreate connections to
+ the source or target servers when the bridge has detected they have failed.
+ The bridge will give up after trying this number of times. -1 represents 'try forever'
+
+
+ Quality Of Service
+ This parameter represents the desired quality of service mode
+ Possible values are:
+
+
+ AT_MOST_ONCE
+
+
+ DUPLICATES_OK
+
+
+ ONCE_AND_ONLY_ONCE
+
+
+ See for a explanation of these
+ modes.
+
+
+ Max Batch Size
+ This represents the maximum number of messages to consume from the source
+ destination before sending them in a batch to the target destination. Its
+ value must >= 1
+
+
+
+ Max Batch Time
+ This represents the maximum number of milliseconds to wait before sending
+ a batch to target, even if the number of messages consumed has not reached
+ MaxBatchSize. Its value must be -1
+ to represent 'wait forever', or >= 1 to specify an actual
+ time
+
+
+ Subscription Name
+ If the source destination represents a topic, and you want to consume from
+ the topic using a durable subscription then this parameter represents the
+ durable subscription name
+
+
+ Client ID
+ If the source destination represents a topic, and you want to consume from
+ the topic using a durable subscription then this attribute represents the
+ the JMS client ID to use when creating/looking up the durable
+ subscription
+
+
+ Add MessageID In Header
+ If true, then the original message's message ID will be
+ appended in the message sent to the destination in the header HORNETQ_BRIDGE_MSG_ID_LIST. If the message is bridged more
+ than once, each message ID will be appended. This enables a distributed
+ request-response pattern to be used
+
+ when you receive the message you can send back a response using the
+ correlation id of the first message id, so when the original sender gets
+ it back it will be able to correlate it.
+
+
+
+ MBean Server
+ To manage the JMS Bridge using JMX, set the MBeanServer where the JMS Bridge MBean
+ must be registered (e.g. the JVM Platform MBeanServer or JBoss AS MBeanServer)
+
+
+ ObjectName
+ If you set the MBeanServer, you also need to set the ObjectName used to register
+ the JMS Bridge MBean (must be unique)
+
+
+ The "transactionManager" property points to a JTA transaction manager implementation.
+ HornetQ doesn't ship with such an implementation, but one is available in the JBoss
+ Community. If you are running HornetQ in standalone mode and wish to use a JMS bridge
+ simply download the latest version of JBossTS from http://www.jboss.org/jbosstm/downloads
+ and add it to HornetQ's classpath. If you are running HornetQ with JBoss AS then you
+ won't need to do this as JBoss AS ships with a JTA transaction manager already. The
+ bean definition for the transaction manager would look something like this:
+
+ <bean name="RealTransactionManager" class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple"/>
+
+
+ Source and Target Connection Factories
+ The source and target connection factory factories are used to create the
+ connection factory used to create the connection for the source or target
+ server.
+ The configuration example above uses the default implementation provided by
+ HornetQ that looks up the connection factory using JNDI. For other Application
+ Servers or JMS providers a new implementation may have to be provided. This can
+ easily be done by implementing the interface org.hornetq.jms.bridge.ConnectionFactoryFactory.
+
+
+ Source and Target Destination Factories
+ Again, similarly, these are used to create or lookup up the destinations.
+ In the configuration example above, we have used the default provided by HornetQ
+ that looks up the destination using JNDI.
+ A new implementation can be provided by implementing org.hornetq.jms.bridge.DestinationFactory interface.
+
+
+ Quality Of Service
+ The quality of service modes used by the bridge are described here in more
+ detail.
+
+ AT_MOST_ONCE
+ With this QoS mode messages will reach the destination from the source at most
+ once. The messages are consumed from the source and acknowledged before sending
+ to the destination. Therefore there is a possibility that if failure occurs
+ between removing them from the source and them arriving at the destination they
+ could be lost. Hence delivery will occur at most once.
+ This mode is available for both durable and non-durable messages.
+
+
+ DUPLICATES_OK
+ With this QoS mode, the messages are consumed from the source and then
+ acknowledged after they have been successfully sent to the destination.
+ Therefore there is a possibility that if failure occurs after sending to the
+ destination but before acknowledging them, they could be sent again when the
+ system recovers. I.e. the destination might receive duplicates after a
+ failure.
+ This mode is available for both durable and non-durable messages.
+
+
+ ONCE_AND_ONLY_ONCE
+ This QoS mode ensures messages will reach the destination from the source once
+ and only once. (Sometimes this mode is known as "exactly once"). If both the
+ source and the destination are on the same HornetQ server instance then this can
+ be achieved by sending and acknowledging the messages in the same local
+ transaction. If the source and destination are on different servers this is
+ achieved by enlisting the sending and consuming sessions in a JTA transaction.
+ The JTA transaction is controlled by JBoss Transactions JTA * implementation
+ which is a fully recovering transaction manager, thus providing a very high
+ degree of durability. If JTA is required then both supplied connection factories
+ need to be XAConnectionFactory implementations. This is likely to be the slowest
+ mode since it requires extra persistence for the transaction logging.
+ This mode is only available for durable messages.
+
+ For a specific application it may possible to provide once and only once
+ semantics without using the ONCE_AND_ONLY_ONCE QoS level. This can be done
+ by using the DUPLICATES_OK mode and then checking for duplicates at the
+ destination and discarding them. Some JMS servers provide automatic
+ duplicate message detection functionality, or this may be possible to
+ implement on the application level by maintaining a cache of received
+ message ids on disk and comparing received messages to them. The cache would
+ only be valid for a certain period of time so this approach is not as
+ watertight as using ONCE_AND_ONLY_ONCE but may be a good choice depending on
+ your specific application.
+
+
+
+ Time outs and the JMS bridge
+ There is a possibility that the target or source server will not be available at some point in time.
+ If this occurs then the bridge will try Max Retries to reconnect every
+ Failure Retry Interval milliseconds as specified in the JMS Bridge definition.
+ However since a third party JNDI is used, in this case the JBoss naming server, it is possible for the
+ JNDI lookup to hang if the network were to disappear during the JNDI lookup. To stop this from occurring the JNDI
+ definition can be configured to time out if this occurs. To do this set the jnp.timeout
+ and the jnp.sotimeout on the Initial Context definition. The first sets the connection
+ timeout for the initial connection and the second the read timeout for the socket.
+
+ Once the initial JNDI connection has succeeded all calls are made using RMI. If you want to control
+ the timeouts for the RMI connections then this can be done via system properties. JBoss uses Sun's RMI
+ and the properties can be found here.
+ The default connection timeout is 10 seconds and the default read timeout is 18 seconds.
+
+ If you implement your own factories for looking up JMS resources then you will have to bear in mind timeout issues.
+
+
+ Examples
+ Please see which shows how to configure
+ and use a JMS Bridge with JBoss AS to send messages to the source destination and consume them
+ from the target destination.
+ Please see which shows how to configure
+ and use a JMS Bridge between two standalone HornetQ servers.
+
+
+
diff --git a/docs/user-manual/en/jms-core-mapping.xml b/docs/user-manual/en/jms-core-mapping.xml
new file mode 100644
index 0000000000..bc80b552af
--- /dev/null
+++ b/docs/user-manual/en/jms-core-mapping.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Mapping JMS Concepts to the Core API
+ This chapter describes how JMS destinations are mapped to HornetQ addresses.
+ HornetQ core is JMS-agnostic. It does not have any concept of a JMS topic. A JMS topic is
+ implemented in core as an address (the topic name) with zero or more queues bound to it.
+ Each queue bound to that address represents a topic subscription. Likewise, a JMS queue is
+ implemented as an address (the JMS queue name) with one single queue bound to it which
+ represents the JMS queue.
+ By convention, all JMS queues map to core queues where the core queue name has the string
+ jms.queue. prepended to it. E.g. the JMS queue with the name
+ "orders.europe" would map to the core queue with the name "jms.queue.orders.europe". The
+ address at which the core queue is bound is also given by the core queue name.
+ For JMS topics the address at which the queues that represent the subscriptions are bound
+ is given by prepending the string "jms.topic." to the name of the JMS topic. E.g. the JMS
+ topic with name "news.europe" would map to the core address "jms.topic.news.europe"
+ In other words if you send a JMS message to a JMS queue with name "orders.europe" it will
+ get routed on the server to any core queues bound to the address "jms.queue.orders.europe".
+ If you send a JMS message to a JMS topic with name "news.europe" it will get routed on the
+ server to any core queues bound to the address "jms.topic.news.europe".
+ If you want to configure settings for a JMS Queue with the name "orders.europe", you need
+ to configure the corresponding core queue "jms.queue.orders.europe":
+
+<!-- expired messages in JMS Queue "orders.europe" will be sent to the JMS Queue "expiry.europe" -->
+<address-setting match="jms.queue.orders.europe">
+ <expiry-address>jms.queue.expiry.europe</expiry-address>
+ ...
+</address-setting>
+
diff --git a/docs/user-manual/en/large-messages.xml b/docs/user-manual/en/large-messages.xml
new file mode 100644
index 0000000000..f28083a62c
--- /dev/null
+++ b/docs/user-manual/en/large-messages.xml
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Large Messages
+ HornetQ supports sending and receiving of huge messages, even when the client and server
+ are running with limited memory. The only realistic limit to the size of a message that can
+ be sent or consumed is the amount of disk space you have available. We have tested sending
+ and consuming messages up to 8 GiB in size with a client and server running in just 50MiB of
+ RAM!
+ To send a large message, the user can set an InputStream on a message
+ body, and when that message is sent, HornetQ will read the InputStream. A
+ FileInputStream could be used for example to send a huge message from
+ a huge file on disk.
+ As the InputStream is read the data is sent to the server as a stream
+ of fragments. The server persists these fragments to disk as it receives them and when the
+ time comes to deliver them to a consumer they are read back of the disk, also in fragments
+ and sent down the wire. When the consumer receives a large message it initially receives
+ just the message with an empty body, it can then set an OutputStream on
+ the message to stream the huge message body to a file on disk or elsewhere. At no time is
+ the entire message body stored fully in memory, either on the client or the server.
+
+ Configuring the server
+ Large messages are stored on a disk directory on the server side, as configured on the
+ main configuration file.
+ The configuration property large-messages-directory specifies where
+ large messages are stored.
+
+<configuration xmlns="urn:hornetq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd">
+...
+<large-messages-directory>/data/large-messages</large-messages-directory>
+...
+</configuration
+ By default the large message directory is data/largemessages
+ For the best performance we recommend large messages directory is stored on a
+ different physical volume to the message journal or paging directory.
+
+
+ Configuring Parameters
+ Any message larger than a certain size is considered a large message. Large messages
+ will be split up and sent in fragments. This is determined by the parameter min-large-message-size
+
+ HornetQ messages are encoded using 2 bytes per character so if the message data is filled
+ with ASCII characters (which are 1 byte) the size of the resulting HornetQ message would roughly
+ double. This is important when calculating the size of a "large" message as it may appear to be
+ less than the min-large-message-size before it is sent, but it then turns into
+ a "large" message once it is encoded.
+
+ The default value is 100KiB.
+
+ Using Core API
+ If the HornetQ Core API is used, the minimal large message size is specified by
+ ServerLocator.setMinLargeMessageSize.
+
+ServerLocator locator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName()))
+
+locator.setMinLargeMessageSize(25 * 1024);
+
+ClientSessionFactory factory = HornetQClient.createClientSessionFactory();
+ will provide more information
+ on how to instantiate the session factory.
+
+
+ Using JMS
+ If JNDI is used to look up the connection factory, the minimum large message size
+ is specified in hornetq-jms.xml
+ ...
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ <entry name="XAConnectionFactory"/>
+ </entries>
+
+ <min-large-message-size>250000</min-large-message-size>
+</connection-factory>
+...
+ If the connection factory is being instantiated directly, the minimum large
+ message size is specified by HornetQConnectionFactory.setMinLargeMessageSize.
+
+
+ Compressed Large Messages
+
+ You can choose to send large messages in compressed form using
+ compress-large-messages attributes.
+
+
+ compress-large-messages
+ If you specify the boolean property compress-large-messages on
+ the server locator or ConnectionFactory as true, The
+ system will use the ZIP algorithm to compress the message body as the message is
+ transferred to the server's side. Notice that there's no special treatment at the
+ server's side, all the compressing and uncompressing is done at the client.
+ If the compressed size of a large message is below
+ min-large-message-size, it is sent to server as regular messages. This means
+ that the message won't be written into the server's large-message
+ data directory, thus reducing the disk I/O.
+
+
+ If you use JMS, you can achieve large messages compression by configuring your
+ connection factories. For example,
+ ...
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+...
+ <compress-large-messages>true</compress-large-messages>
+</connection-factory>
+...
+
+
+
+
+ Streaming large messages
+ HornetQ supports setting the body of messages using input and output streams (java.lang.io)
+ These streams are then used directly for sending (input streams) and receiving (output
+ streams) messages.
+ When receiving messages there are 2 ways to deal with the output stream; you may
+ choose to block while the output stream is recovered using the method ClientMessage.saveOutputStream or alternatively using the method ClientMessage.setOutputstream which will asynchronously write the message
+ to the stream. If you choose the latter the consumer must be kept alive until the
+ message has been fully received.
+ You can use any kind of stream you like. The most common use case is to send files
+ stored in your disk, but you could also send things like JDBC Blobs, SocketInputStream, things you recovered from HTTPRequests etc. Anything as long as it implements java.io.InputStream for sending messages or java.io.OutputStream for receiving them.
+
+ Streaming over Core API
+ The following table shows a list of methods available at ClientMessage which are also available through JMS by the use of
+ object properties.
+
+ org.hornetq.api.core.client.ClientMessage API
+
+
+
+
+
+
+ Name
+ Description
+ JMS Equivalent Property
+
+
+
+
+ setBodyInputStream(InputStream)
+ Set the InputStream used to read a message body when sending
+ it.
+ JMS_HQ_InputStream
+
+
+ setOutputStream(OutputStream)
+ Set the OutputStream that will receive the body of a message.
+ This method does not block.
+ JMS_HQ_OutputStream
+
+
+ saveOutputStream(OutputStream)
+ Save the body of the message to the OutputStream. It will block until the entire content
+ is transferred to the OutputStream.
+ JMS_HQ_SaveStream
+
+
+
+
+ To set the output stream when receiving a core message:
+
+...
+ClientMessage msg = consumer.receive(...);
+
+
+// This will block here until the stream was transferred
+msg.saveOutputStream(someOutputStream);
+
+ClientMessage msg2 = consumer.receive(...);
+
+// This will not wait the transfer to finish
+msg.setOutputStream(someOtherOutputStream);
+...
+ Set the input stream when sending a core message:
+
+...
+ClientMessage msg = session.createMessage();
+msg.setInputStream(dataInputStream);
+...
+ Notice also that for messages with more than 2GiB the getBodySize() will return
+ invalid values since this is an integer (which is also exposed to the JMS API). On
+ those cases you can use the message property _HQ_LARGE_SIZE.
+
+
+ Streaming over JMS
+ When using JMS, HornetQ maps the streaming methods on the core API (see ) by setting object properties . You
+ can use the method Message.setObjectProperty to set the input and
+ output streams.
+ The InputStream can be defined through the JMS Object Property
+ JMS_HQ_InputStream on messages being sent:
+
+BytesMessage message = session.createBytesMessage();
+
+FileInputStream fileInputStream = new FileInputStream(fileInput);
+
+BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream);
+
+message.setObjectProperty("JMS_HQ_InputStream", bufferedInput);
+
+someProducer.send(message);
+ The OutputStream can be set through the JMS Object Property
+ JMS_HQ_SaveStream on messages being received in a blocking way.
+
+BytesMessage messageReceived = (BytesMessage)messageConsumer.receive(120000);
+
+File outputFile = new File("huge_message_received.dat");
+
+FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
+
+BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream);
+
+// This will block until the entire content is saved on disk
+messageReceived.setObjectProperty("JMS_HQ_SaveStream", bufferedOutput);
+ Setting the OutputStream could also be done in a non blocking
+ way using the property JMS_HQ_OutputStream.
+
+// This won't wait the stream to finish. You need to keep the consumer active.
+messageReceived.setObjectProperty("JMS_HQ_OutputStream", bufferedOutput);
+
+ When using JMS, Streaming large messages are only supported on StreamMessage and BytesMessage.
+
+
+
+
+ Streaming Alternative
+ If you choose not to use the InputStream or OutputStream capability of HornetQ You could still access the data
+ directly in an alternative fashion.
+ On the Core API just get the bytes of the body as you normally would.
+
+ClientMessage msg = consumer.receive();
+
+byte[] bytes = new byte[1024];
+for (int i = 0 ; i < msg.getBodySize(); i += bytes.length)
+{
+ msg.getBody().readBytes(bytes);
+ // Whatever you want to do with the bytes
+}
+ If using JMS API, BytesMessage and StreamMessage
+ also supports it transparently.
+
+BytesMessage rm = (BytesMessage)cons.receive(10000);
+
+byte data[] = new byte[1024];
+
+for (int i = 0; i < rm.getBodyLength(); i += 1024)
+{
+ int numberOfBytes = rm.readBytes(data);
+ // Do whatever you want with the data
+}
+
+
+ Large message example
+ Please see for an example which shows how
+ large message is configured and used with JMS.
+
+
diff --git a/docs/user-manual/en/last-value-queues.xml b/docs/user-manual/en/last-value-queues.xml
new file mode 100644
index 0000000000..def6115716
--- /dev/null
+++ b/docs/user-manual/en/last-value-queues.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Last-Value Queues
+ Last-Value queues are special queues which discard any messages when a newer message with
+ the same value for a well-defined Last-Value property is put in the queue. In other words, a
+ Last-Value queue only retains the last value.
+ A typical example for Last-Value queue is for stock prices, where you are only interested
+ by the latest value for a particular stock.
+
+ Configuring Last-Value Queues
+ Last-value queues are defined in the address-setting configuration:
+
+<address-setting match="jms.queue.lastValueQueue">
+ <last-value-queue>true</last-value-queue>
+</address-setting>
+ By default, last-value-queue is false. Address wildcards can be used
+ to configure Last-Value queues for a set of addresses (see ).
+
+
+ Using Last-Value Property
+ The property name used to identify the last value is "_HQ_LVQ_NAME"
+ (or the constant Message.HDR_LAST_VALUE_NAME from the Core API).
+ For example, if two messages with the same value for the Last-Value property are sent to
+ a Last-Value queue, only the latest message will be kept in the queue:
+
+// send 1st message with Last-Value property set to STOCK_NAME
+TextMessage message = session.createTextMessage("1st message with Last-Value property set");
+message.setStringProperty("_HQ_LVQ_NAME", "STOCK_NAME");
+producer.send(message);
+
+// send 2nd message with Last-Value property set to STOCK_NAME
+message = session.createTextMessage("2nd message with Last-Value property set");
+message.setStringProperty("_HQ_LVQ_NAME", "STOCK_NAME");
+producer.send(message);
+
+...
+
+// only the 2nd message will be received: it is the latest with
+// the Last-Value property set
+TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+System.out.format("Received message: %s\n", messageReceived.getText());
+
+
+ Example
+ See for an example which shows how last
+ value queues are configured and used with JMS.
+
+
diff --git a/docs/user-manual/en/libaio.xml b/docs/user-manual/en/libaio.xml
new file mode 100644
index 0000000000..d0e2c760a4
--- /dev/null
+++ b/docs/user-manual/en/libaio.xml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Libaio Native Libraries
+ HornetQ distributes a native library, used as a bridge between HornetQ and Linux
+ libaio.
+ libaio is a library, developed as part of the Linux kernel project.
+ With libaio we submit writes to the operating system where they are
+ processed asynchronously. Some time later the OS will call our code back when they have been
+ processed.
+ We use this in our high performance journal if configured to do so, please see .
+ These are the native libraries distributed by HornetQ:
+
+
+ libHornetQAIO32.so - x86 32 bits
+
+
+ libHornetQAIO64.so - x86 64 bits
+
+
+ When using libaio, HornetQ will always try loading these files as long as they are on the
+ library path.
+
+ Compiling the native libraries
+ In the case that you are using Linux on a platform other than x86_32 or x86_64
+ (for example Itanium 64 bits or IBM Power) you may need to compile the native library, since we
+ do not distribute binaries for those platforms with the release.
+
+ Install requirements
+
+ At the moment the native layer is only available on Linux. If you are in a
+ platform other than Linux the native compilation will not work
+
+ The native library uses autoconf what makes the compilation process easy, however you need to
+ install extra packages as a requirement for compilation:
+
+
+ gcc - C Compiler
+
+
+ gcc-c++ or g++ - Extension to gcc with support for C++
+
+
+ autoconf - Tool for automating native build process
+
+
+ make - Plain old make
+
+
+ automake - Tool for automating make generation
+
+
+ libtool - Tool for link editing native libraries
+
+
+ libaio - library to disk asynchronous IO kernel functions
+
+
+ libaio-dev - Compilation support for libaio
+
+
+ A full JDK installed with the environment variable JAVA_HOME set to its
+ location
+
+
+ To perform this installation on RHEL or Fedora, you can simply type this at a
+ command line:
+ sudo yum install automake libtool autoconf gcc-c++ gcc libaio libaio-devel make
+ Or on Debian systems:
+ sudo apt-get install automake libtool autoconf gcc-g++ gcc libaio libaio-dev make
+
+ You could find a slight variation of the package names depending on the
+ version and Linux distribution. (for example gcc-c++ on Fedora versus g++ on
+ Debian systems)
+
+
+
+ Invoking the compilation
+ In the distribution, in the native-src directory, execute the
+ shell script bootstrap. This script will invoke automake and make what will create all the make
+ files and the native library.
+ someUser@someBox:/messaging-distribution/native-src$ ./bootstrap
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /bin/mkdir -p
+
+...
+
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating ./src/Makefile
+config.status: creating config.h
+config.status: config.h is unchanged
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+...
+ The produced library will be at ./native-src/src/.libs/libHornetQAIO.so. Simply move that file over
+ bin on the distribution or the place you have chosen on the
+ library path.
+ If you want to perform changes on the HornetQ libaio code, you could just call
+ make directly at the native-src directory.
+
+
+
diff --git a/docs/user-manual/en/logging.xml b/docs/user-manual/en/logging.xml
new file mode 100644
index 0000000000..b21b587375
--- /dev/null
+++ b/docs/user-manual/en/logging.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Logging
+ HornetQ uses the JBoss Logging framework to do its logging and is configurable via the logging.properties
+ file found in the configuration directories. This is configured by Default to log to both the console and to a file.
+ There are 6 loggers available which are as follows:
+
+ Global Configuration Properties
+
+
+
+
+
+ Logger
+ Logger Description
+
+
+
+
+ org.jboss.logging
+ Logs any calls not handled by the HornetQ loggers
+
+
+ org.hornetq.core.server
+ Logs the core server
+
+
+ org.hornetq.utils
+ Logs utility calls
+
+
+ org.hornetq.journal
+ Logs Journal calls
+
+
+ org.hornetq.jms
+ Logs JMS calls
+
+
+ org.hornetq.integration.bootstrap
+ Logs bootstrap calls
+
+
+
+ you can configure the levels on these loggers independently in the appropriate logging.properties
+ file
+
+ Paging Configuration Parameters
+
+
+
+
+
+
+ Property Name
+ Description
+ Default
+
+
+
+
+ paging-directory
+ Where page files are stored. HornetQ will create one folder for
+ each address being paged under this configured location.
+ data/paging
+
+
+
+
+
+
+
+ Paging Mode
+ As soon as messages delivered to an address exceed the configured size, that address
+ alone goes into page mode.
+
+ Paging is done individually per address. If you configure a max-size-bytes for an
+ address, that means each matching address will have a maximum size that you
+ specified. It DOES NOT mean that the total overall size of all matching addresses is
+ limited to max-size-bytes.
+
+
+ Configuration
+ Configuration is done at the address settings, done at the main configuration file
+ (hornetq-configuration.xml).
+
+<address-settings>
+ <address-setting match="jms.someaddress">
+ <max-size-bytes>104857600</max-size-bytes>
+ <page-size-bytes>10485760</page-size-bytes>
+ <address-full-policy>PAGE</address-full-policy>
+ </address-setting>
+</address-settings>
+ This is the list of available parameters on the address settings.
+
+
+ Paging Address Settings
+
+
+
+
+
+
+ Property Name
+ Description
+ Default
+
+
+
+
+ max-size-bytes
+ What's the max memory the address could have before entering
+ on page mode.
+ -1 (disabled)
+
+
+ page-size-bytes
+ The size of each page file used on the paging system
+ 10MiB (10 * 1024 * 1024 bytes)
+
+
+ address-full-policy
+ This must be set to PAGE for paging to enable. If the value
+ is PAGE then further messages will be paged to disk. If the
+ value is DROP then further messages will be silently dropped. If
+ the value is FAIL then the messages will be dropped and the client
+ message producers will receive an exception. If the value is
+ BLOCK then client message producers will block when they try and
+ send further messages.
+ PAGE
+
+
+ page-max-cache-size
+ The system will keep up to <page-max-cache-size page files in memory to
+ optimize IO during paging navigation.
+ 5
+
+
+
+
+
+
+
+
+ Dropping messages
+ Instead of paging messages when the max size is reached, an address can also be
+ configured to just drop messages when the address is full.
+ To do this just set the address-full-policy to DROP in the address settings
+
+
+ Dropping messages and throwing an exception to producers
+ Instead of paging messages when the max size is reached, an address can also be
+ configured to drop messages and also throw an exception on the client-side
+ when the address is full.
+ To do this just set the address-full-policy to FAIL in the address settings
+
+
+ Blocking producers
+ Instead of paging messages when the max size is reached, an address can also be
+ configured to block producers from sending further messages when the address is full,
+ thus preventing the memory being exhausted on the server.
+ When memory is freed up on the server, producers will automatically unblock and be
+ able to continue sending.
+ To do this just set the address-full-policy to BLOCK in the address settings
+ In the default configuration, all addresses are configured to block producers after 10
+ MiB of data are in the address.
+
+
+ Caution with Addresses with Multiple Queues
+ When a message is routed to an address that has multiple queues bound to it, e.g. a
+ JMS subscription in a Topic, there is only 1 copy of the message in memory. Each queue
+ only deals with a reference to this. Because of this the memory is only freed up once
+ all queues referencing the message have delivered it.
+ If you have a single lazy subscription, the entire address will suffer IO performance
+ hit as all the queues will have messages being sent through an extra storage on the
+ paging system.
+ For example:
+
+
+ An address has 10 queues
+
+
+ One of the queues does not deliver its messages (maybe because of a slow
+ consumer).
+
+
+ Messages continually arrive at the address and paging is started.
+
+
+ The other 9 queues are empty even though messages have been sent.
+
+
+ In this example all the other 9 queues will be consuming messages from the page
+ system. This may cause performance issues if this is an undesirable state.
+
+
+ Example
+ See for an example which shows how to use paging
+ with HornetQ.
+
+
diff --git a/docs/user-manual/en/perf-tuning.xml b/docs/user-manual/en/perf-tuning.xml
new file mode 100644
index 0000000000..da0c2ede70
--- /dev/null
+++ b/docs/user-manual/en/perf-tuning.xml
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Performance Tuning
+ In this chapter we'll discuss how to tune HornetQ for optimum performance.
+
+ Tuning persistence
+
+
+ Put the message journal on its own physical volume. If the disk is shared with
+ other processes e.g. transaction co-ordinator, database or other journals which
+ are also reading and writing from it, then this may greatly reduce performance
+ since the disk head may be skipping all over the place between the different
+ files. One of the advantages of an append only journal is that disk head
+ movement is minimised - this advantage is destroyed if the disk is shared. If
+ you're using paging or large messages make sure they're ideally put on separate
+ volumes too.
+
+
+ Minimum number of journal files. Set journal-min-files to a
+ number of files that would fit your average sustainable rate. If you see new
+ files being created on the journal data directory too often, i.e. lots of data
+ is being persisted, you need to increase the minimal number of files, this way
+ the journal would reuse more files instead of creating new data files.
+
+
+ Journal file size. The journal file size should be aligned to the capacity of
+ a cylinder on the disk. The default value 10MiB should be enough on most
+ systems.
+
+
+ Use AIO journal. If using Linux, try to keep your journal type as AIO. AIO
+ will scale better than Java NIO.
+
+
+ Tune journal-buffer-timeout. The timeout can be increased
+ to increase throughput at the expense of latency.
+
+
+ If you're running AIO you might be able to get some better performance by
+ increasing journal-max-io. DO NOT change this parameter if
+ you are running NIO.
+
+
+
+
+ Tuning JMS
+ There are a few areas where some tweaks can be done if you are using the JMS
+ API
+
+
+ Disable message id. Use the setDisableMessageID() method on
+ the MessageProducer class to disable message ids if you don't
+ need them. This decreases the size of the message and also avoids the overhead
+ of creating a unique ID.
+
+
+ Disable message timestamp. Use the setDisableMessageTimeStamp() method on the MessageProducer class to disable message timestamps if you don't
+ need them.
+
+
+ Avoid ObjectMessage. ObjectMessage is
+ convenient but it comes at a cost. The body of a ObjectMessage uses Java serialization to serialize it to bytes.
+ The Java serialized form of even small objects is very verbose so takes up a lot
+ of space on the wire, also Java serialization is slow compared to custom
+ marshalling techniques. Only use ObjectMessage if you really
+ can't use one of the other message types, i.e. if you really don't know the type
+ of the payload until run-time.
+
+
+ Avoid AUTO_ACKNOWLEDGE. AUTO_ACKNOWLEDGE
+ mode requires an acknowledgement to be sent from the server for each message
+ received on the client, this means more traffic on the network. If you can, use
+ DUPS_OK_ACKNOWLEDGE or use CLIENT_ACKNOWLEDGE or a transacted session and batch up many
+ acknowledgements with one acknowledge/commit.
+
+
+ Avoid durable messages. By default JMS messages are durable. If you don't
+ really need durable messages then set them to be non-durable. Durable messages
+ incur a lot more overhead in persisting them to storage.
+
+
+ Batch many sends or acknowledgements in a single transaction. HornetQ will
+ only require a network round trip on the commit, not on every send or
+ acknowledgement.
+
+
+
+
+ Other Tunings
+ There are various other places in HornetQ where we can perform some tuning:
+
+
+ Use Asynchronous Send Acknowledgements. If you need to send durable messages
+ non transactionally and you need a guarantee that they have reached the server
+ by the time the call to send() returns, don't set durable messages to be sent
+ blocking, instead use asynchronous send acknowledgements to get your
+ acknowledgements of send back in a separate stream, see for more information on this.
+
+
+ Use pre-acknowledge mode. With pre-acknowledge mode, messages are acknowledged
+ before they are sent to the client. This reduces the
+ amount of acknowledgement traffic on the wire. For more information on this, see
+ .
+
+
+ Disable security. You may get a small performance boost by disabling security
+ by setting the security-enabled parameter to false in hornetq-configuration.xml.
+
+
+ Disable persistence. If you don't need message persistence, turn it off
+ altogether by setting persistence-enabled to false in
+ hornetq-configuration.xml.
+
+
+ Sync transactions lazily. Setting journal-sync-transactional to false in
+ hornetq-configuration.xml can give you better
+ transactional persistent performance at the expense of some possibility of loss
+ of transactions on failure. See for more
+ information.
+
+
+ Sync non transactional lazily. Setting journal-sync-non-transactional to false in
+ hornetq-configuration.xml can give you better
+ non-transactional persistent performance at the expense of some possibility of
+ loss of durable messages on failure. See for
+ more information.
+
+
+ Send messages non blocking. Setting block-on-durable-send
+ and block-on-non-durable-send to false in
+ hornetq-jms.xml (if you're using JMS and JNDI) or
+ directly on the ServerLocator. This means you don't have to wait a whole
+ network round trip for every message sent. See
+ for more information.
+
+
+ If you have very fast consumers, you can increase consumer-window-size. This
+ effectively disables consumer flow control.
+
+
+ Socket NIO vs Socket Old IO. By default HornetQ uses old (blocking) on the
+ server and the client side (see the chapter on configuring transports for more
+ information ). NIO is much more scalable
+ but can give you some latency hit compared to old blocking IO. If you need to be
+ able to service many thousands of connections on the server, then you should
+ make sure you're using NIO on the server. However, if don't expect many
+ thousands of connections on the server you can keep the server acceptors using
+ old IO, and might get a small performance advantage.
+
+
+ Use the core API not JMS. Using the JMS API you will have slightly lower
+ performance than using the core API, since all JMS operations need to be
+ translated into core operations before the server can handle them. If using the
+ core API try to use methods that take SimpleString as much as
+ possible. SimpleString, unlike java.lang.String does not
+ require copying before it is written to the wire, so if you re-use SimpleString instances between calls then you can avoid some
+ unnecessary copying.
+
+
+
+
+ Tuning Transport Settings
+
+
+ TCP buffer sizes. If you have a fast network and fast machines you may get a
+ performance boost by increasing the TCP send and receive buffer sizes. See the
+ for more information on this.
+
+ Note that some operating systems like later versions of Linux include TCP
+ auto-tuning and setting TCP buffer sizes manually can prevent auto-tune from
+ working and actually give you worse performance!
+
+
+
+ Increase limit on file handles on the server. If you expect a lot of
+ concurrent connections on your servers, or if clients are rapidly opening and
+ closing connections, you should make sure the user running the server has
+ permission to create sufficient file handles.
+ This varies from operating system to operating system. On Linux systems you
+ can increase the number of allowable open file handles in the file /etc/security/limits.conf e.g. add the lines
+
+serveruser soft nofile 20000
+serveruser hard nofile 20000
+ This would allow up to 20000 file handles to be open by the user serveruser.
+
+
+ Use batch-delay and set direct-deliver
+ to false for the best throughput for very small messages. HornetQ comes with a
+ preconfigured connector/acceptor pair (netty-throughput) in
+ hornetq-configuration.xml and JMS connection factory
+ (ThroughputConnectionFactory) in hornetq-jms.xmlwhich can be used to give the very best
+ throughput, especially for small messages. See the for more information on this.
+
+
+
+
+ Tuning the VM
+ We highly recommend you use the latest Java JVM for the best performance. We test
+ internally using the Sun JVM, so some of these tunings won't apply to JDKs from other
+ providers (e.g. IBM or JRockit)
+
+
+ Garbage collection. For smooth server operation we recommend using a parallel
+ garbage collection algorithm, e.g. using the JVM argument -XX:+UseParallelOldGC on Sun JDKs.
+
+
+ Memory settings. Give as much memory as you can to the server. HornetQ can run
+ in low memory by using paging (described in ) but if it
+ can run with all queues in RAM this will improve performance. The amount of
+ memory you require will depend on the size and number of your queues and the
+ size and number of your messages. Use the JVM arguments -Xms
+ and -Xmx to set server available RAM. We recommend setting
+ them to the same high value.
+
+
+ Aggressive options. Different JVMs provide different sets of JVM tuning
+ parameters, for the Sun Hotspot JVM the full list of options is available here. We recommend at least using -XX:+AggressiveOpts and
+ -XX:+UseFastAccessorMethods. You may get some mileage with the
+ other tuning parameters depending on your OS platform and application usage
+ patterns.
+
+
+
+
+ Avoiding Anti-Patterns
+
+
+ Re-use connections / sessions / consumers / producers. Probably the most
+ common messaging anti-pattern we see is users who create a new
+ connection/session/producer for every message they send or every message they
+ consume. This is a poor use of resources. These objects take time to create and
+ may involve several network round trips. Always re-use them.
+
+ Some popular libraries such as the Spring JMS Template are known to use
+ these anti-patterns. If you're using Spring JMS Template and you're getting
+ poor performance you know why. Don't blame HornetQ! The Spring JMS Template
+ can only safely be used in an app server which caches JMS sessions (e.g.
+ using JCA), and only then for sending messages. It cannot be safely be used
+ for synchronously consuming messages, even in an app server.
+
+
+
+ Avoid fat messages. Verbose formats such as XML take up a lot of space on the
+ wire and performance will suffer as result. Avoid XML in message bodies if you
+ can.
+
+
+ Don't create temporary queues for each request. This common anti-pattern
+ involves the temporary queue request-response pattern. With the temporary queue
+ request-response pattern a message is sent to a target and a reply-to header is
+ set with the address of a local temporary queue. When the recipient receives the
+ message they process it then send back a response to the address specified in
+ the reply-to. A common mistake made with this pattern is to create a new
+ temporary queue on each message sent. This will drastically reduce performance.
+ Instead the temporary queue should be re-used for many requests.
+
+
+ Don't use Message-Driven Beans for the sake of it. As soon as you start using
+ MDBs you are greatly increasing the codepath for each message received compared
+ to a straightforward message consumer, since a lot of extra application server
+ code is executed. Ask yourself do you really need MDBs? Can you accomplish the
+ same task using just a normal message consumer?
+
+
+
+
diff --git a/docs/user-manual/en/persistence.xml b/docs/user-manual/en/persistence.xml
new file mode 100644
index 0000000000..1e15c65ad3
--- /dev/null
+++ b/docs/user-manual/en/persistence.xml
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Persistence
+ In this chapter we will describe how persistence works with HornetQ and how to configure
+ it.
+ HornetQ ships with a high performance journal. Since HornetQ handles its own persistence,
+ rather than relying on a database or other 3rd party persistence engine it is very highly
+ optimised for the specific messaging use cases.
+ A HornetQ journal is an append only journal. It consists of a set of
+ files on disk. Each file is pre-created to a fixed size and initially filled with padding.
+ As operations are performed on the server, e.g. add message, update message, delete message,
+ records are appended to the journal. When one journal file is full we move to the next
+ one.
+ Because records are only appended, i.e. added to the end of the journal we minimise disk
+ head movement, i.e. we minimise random access operations which is typically the slowest
+ operation on a disk.
+ Making the file size configurable means that an optimal size can be chosen, i.e. making
+ each file fit on a disk cylinder. Modern disk topologies are complex and we are not in
+ control over which cylinder(s) the file is mapped onto so this is not an exact science. But
+ by minimising the number of disk cylinders the file is using, we can minimise the amount of
+ disk head movement, since an entire disk cylinder is accessible simply by the disk rotating
+ - the head does not have to move.
+ As delete records are added to the journal, HornetQ has a sophisticated file garbage
+ collection algorithm which can determine if a particular journal file is needed any more -
+ i.e. has all its data been deleted in the same or other files. If so, the file can be
+ reclaimed and re-used.
+ HornetQ also has a compaction algorithm which removes dead space from the journal and
+ compresses up the data so it takes up less files on disk.
+ The journal also fully supports transactional operation if required, supporting both local
+ and XA transactions.
+ The majority of the journal is written in Java, however we abstract out the interaction
+ with the actual file system to allow different pluggable implementations. HornetQ ships with
+ two implementations:
+
+
+ Java NIO.
+ The first implementation uses standard Java NIO to interface with the file system.
+ This provides extremely good performance and runs on any platform where there's a
+ Java 6+ runtime.
+
+
+ Linux Asynchronous IO
+ The second implementation uses a thin native code wrapper to talk to the Linux
+ asynchronous IO library (AIO). With AIO, HornetQ will be called back when the data
+ has made it to disk, allowing us to avoid explicit syncs altogether and simply send
+ back confirmation of completion when AIO informs us that the data has been
+ persisted.
+ Using AIO will typically provide even better performance than using Java
+ NIO.
+ The AIO journal is only available when running Linux kernel 2.6 or later and after
+ having installed libaio (if it's not already installed). For instructions on how to
+ install libaio please see .
+ Also, please note that AIO will only work with the following file systems: ext2,
+ ext3, ext4, jfs, xfs. With other file systems, e.g. NFS it may appear to work, but
+ it will fall back to a slower synchronous behaviour. Don't put the journal on a NFS
+ share!
+ For more information on libaio please see .
+ libaio is part of the kernel project.
+
+
+ The standard HornetQ core server uses two instances of the journal:
+
+
+ Bindings journal.
+ This journal is used to store bindings related data. That includes the set of
+ queues that are deployed on the server and their attributes. It also stores data
+ such as id sequence counters.
+ The bindings journal is always a NIO journal as it is typically low throughput
+ compared to the message journal.
+ The files on this journal are prefixed as hornetq-bindings.
+ Each file has a bindings extension. File size is 1048576, and it is located at the bindings folder.
+
+
+ JMS journal.
+ This journal instance stores all JMS related data, This is basically any JMS
+ Queues, Topics and Connection Factories and any JNDI bindings for these
+ resources.
+ Any JMS Resources created via the management API will be persisted to this
+ journal. Any resources configured via configuration files will not. The JMS Journal
+ will only be created if JMS is being used.
+ The files on this journal are prefixed as hornetq-jms. Each
+ file has a jms extension. File size is 1048576, and it is located at the bindings folder.
+
+
+ Message journal.
+ This journal instance stores all message related data, including the message
+ themselves and also duplicate-id caches.
+ By default HornetQ will try and use an AIO journal. If AIO is not available, e.g.
+ the platform is not Linux with the correct kernel version or AIO has not been
+ installed then it will automatically fall back to using Java NIO which is available
+ on any Java platform.
+ The files on this journal are prefixed as hornetq-data. Each
+ file has a hq extension. File size is by the default 10485760 (configurable), and it is located at the journal
+ folder.
+
+
+ For large messages, HornetQ persists them outside the message journal. This is discussed
+ in .
+ HornetQ can also be configured to page messages to disk in low memory situations. This is
+ discussed in .
+ If no persistence is required at all, HornetQ can also be configured not to persist any
+ data at all to storage as discussed in .
+
+ Configuring the bindings journal
+ The bindings journal is configured using the following attributes in hornetq-configuration.xml
+
+
+ bindings-directory
+ This is the directory in which the bindings journal lives. The default value
+ is data/bindings.
+
+
+ create-bindings-dir
+ If this is set to true then the bindings directory will be
+ automatically created at the location specified in bindings-directory if it does not already exist. The default
+ value is true
+
+
+
+
+ Configuring the jms journal
+ The jms config shares its configuration with the bindings journal.
+
+
+ Configuring the message journal
+ The message journal is configured using the following attributes in hornetq-configuration.xml
+
+
+ journal-directory
+ This is the directory in which the message journal lives. The default value is
+ data/journal.
+ For the best performance, we recommend the journal is located on its own
+ physical volume in order to minimise disk head movement. If the journal is on a
+ volume which is shared with other processes which might be writing other files
+ (e.g. bindings journal, database, or transaction coordinator) then the disk head
+ may well be moving rapidly between these files as it writes them, thus
+ drastically reducing performance.
+ When the message journal is stored on a SAN we recommend each journal instance
+ that is stored on the SAN is given its own LUN (logical unit).
+
+
+ create-journal-dir
+ If this is set to true then the journal directory will be
+ automatically created at the location specified in journal-directory if it does not already exist. The default value
+ is true
+
+
+ journal-type
+ Valid values are NIO or ASYNCIO.
+ Choosing NIO chooses the Java NIO journal. Choosing
+ AIO chooses the Linux asynchronous IO journal. If you
+ choose AIO but are not running Linux or you do not have
+ libaio installed then HornetQ will detect this and automatically fall back to
+ using NIO.
+
+
+ journal-sync-transactional
+ If this is set to true then HornetQ will make sure all transaction data is
+ flushed to disk on transaction boundaries (commit, prepare and rollback). The
+ default value is true.
+
+
+ journal-sync-non-transactional
+ If this is set to true then HornetQ will make sure non transactional message
+ data (sends and acknowledgements) are flushed to disk each time. The default
+ value for this is true.
+
+
+ journal-file-size
+ The size of each journal file in bytes. The default value for this is 10485760 bytes (10MiB).
+
+
+ journal-min-files
+ The minimum number of files the journal will maintain. When HornetQ starts and
+ there is no initial message data, HornetQ will pre-create journal-min-files number of files.
+ Creating journal files and filling them with padding is a fairly expensive
+ operation and we want to minimise doing this at run-time as files get filled. By
+ pre-creating files, as one is filled the journal can immediately resume with the
+ next one without pausing to create it.
+ Depending on how much data you expect your queues to contain at steady state
+ you should tune this number of files to match that total amount of data.
+
+
+ journal-max-io
+ Write requests are queued up before being submitted to the system for
+ execution. This parameter controls the maximum number of write requests that can
+ be in the IO queue at any one time. If the queue becomes full then writes will
+ block until space is freed up.
+ When using NIO, this value should always be equal to 1
+ When using AIO, the default should be 500.
+ The system maintains different defaults for this parameter depending on whether
+ it's NIO or AIO (default for NIO is 1, default for AIO is 500)
+ There is a limit and the total max AIO can't be higher than what is configured
+ at the OS level (/proc/sys/fs/aio-max-nr) usually at 65536.
+
+
+ journal-buffer-timeout
+ Instead of flushing on every write that requires a flush, we maintain an
+ internal buffer, and flush the entire buffer either when it is full, or when a
+ timeout expires, whichever is sooner. This is used for both NIO and AIO and
+ allows the system to scale better with many concurrent writes that require
+ flushing.
+ This parameter controls the timeout at which the buffer will be flushed if it
+ hasn't filled already. AIO can typically cope with a higher flush rate than NIO,
+ so the system maintains different defaults for both NIO and AIO (default for NIO
+ is 3333333 nanoseconds - 300 times per second, default for AIO is 500000
+ nanoseconds - ie. 2000 times per second).
+
+ By increasing the timeout, you may be able to increase system throughput
+ at the expense of latency, the default parameters are chosen to give a
+ reasonable balance between throughput and latency.
+
+
+
+ journal-buffer-size
+ The size of the timed buffer on AIO. The default value is 490KiB.
+
+
+ journal-compact-min-files
+ The minimal number of files before we can consider compacting the journal. The
+ compacting algorithm won't start until you have at least journal-compact-min-files
+ The default for this parameter is 10
+
+
+ journal-compact-percentage
+ The threshold to start compacting. When less than this percentage is
+ considered live data, we start compacting. Note also that compacting won't kick
+ in until you have at least journal-compact-min-files data
+ files on the journal
+ The default for this parameter is 30
+
+
+
+
+ An important note on disabling disk write cache.
+
+ Most disks contain hardware write caches. A write cache can increase the apparent
+ performance of the disk because writes just go into the cache and are then lazily
+ written to the disk later.
+ This happens irrespective of whether you have executed a fsync() from the
+ operating system or correctly synced data from inside a Java program!
+ By default many systems ship with disk write cache enabled. This means that even
+ after syncing from the operating system there is no guarantee the data has actually
+ made it to disk, so if a failure occurs, critical data can be lost.
+ Some more expensive disks have non volatile or battery backed write caches which
+ won't necessarily lose data on event of failure, but you need to test them!
+ If your disk does not have an expensive non volatile or battery backed cache and
+ it's not part of some kind of redundant array (e.g. RAID), and you value your data
+ integrity you need to make sure disk write cache is disabled.
+ Be aware that disabling disk write cache can give you a nasty shock performance
+ wise. If you've been used to using disks with write cache enabled in their default
+ setting, unaware that your data integrity could be compromised, then disabling it
+ will give you an idea of how fast your disk can perform when acting really
+ reliably.
+ On Linux you can inspect and/or change your disk's write cache settings using the
+ tools hdparm (for IDE disks) or sdparm or
+ sginfo (for SDSI/SATA disks)
+ On Windows you can check / change the setting by right clicking on the disk and
+ clicking properties.
+
+
+
+ Installing AIO
+ The Java NIO journal gives great performance, but If you are running HornetQ using
+ Linux Kernel 2.6 or later, we highly recommend you use the AIO
+ journal for the very best persistence performance.
+ It's not possible to use the AIO journal under other operating systems or earlier
+ versions of the Linux kernel.
+ If you are running Linux kernel 2.6 or later and don't already have libaio installed, you can easily install it using the following
+ steps:
+ Using yum, (e.g. on Fedora or Red Hat Enterprise Linux):
+ yum install libaio
+ Using aptitude, (e.g. on Ubuntu or Debian system):
+ apt-get install libaio
+
+
+ Configuring HornetQ for Zero Persistence
+ In some situations, zero persistence is sometimes required for a messaging system.
+ Configuring HornetQ to perform zero persistence is straightforward. Simply set the
+ parameter persistence-enabled in hornetq-configuration.xml to false.
+ Please note that if you set this parameter to false, then zero
+ persistence will occur. That means no bindings data, message data, large message data,
+ duplicate id caches or paging data will be persisted.
+
+
+ Import/Export the Journal Data
+ You may want to inspect the existent records on each one of the journals used by
+ HornetQ, and you can use the export/import tool for that purpose. The export/import are
+ classes located at the hornetq-core.jar, you can export the journal as a text file by
+ using this command:
+ java -cp hornetq-core.jar org.hornetq.core.journal.impl.ExportJournal
+ <JournalDirectory> <JournalPrefix> <FileExtension> <FileSize>
+ <FileOutput>
+ To import the file as binary data on the journal (Notice you also require
+ netty.jar):
+ java -cp hornetq-core.jar:netty.jar org.hornetq.core.journal.impl.ImportJournal
+ <JournalDirectory> <JournalPrefix> <FileExtension> <FileSize>
+ <FileInput>
+
+
+ JournalDirectory: Use the configured folder for your selected folder. Example:
+ ./hornetq/data/journal
+
+
+ JournalPrefix: Use the prefix for your selected journal, as discussed
+ here
+
+
+ FileExtension: Use the extension for your selected journal, as discussed
+ here
+
+
+ FileSize: Use the size for your selected journal, as discussed here
+
+
+ FileOutput: text file that will contain the exported data
+
+
+
+
diff --git a/docs/user-manual/en/pre-acknowledge.xml b/docs/user-manual/en/pre-acknowledge.xml
new file mode 100644
index 0000000000..81abbe9c7d
--- /dev/null
+++ b/docs/user-manual/en/pre-acknowledge.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %BOOK_ENTITIES;
+ ]>
+
+ Extra Acknowledge Modes
+ JMS specifies 3 acknowledgement modes:
+
+
+ AUTO_ACKNOWLEDGE
+
+
+ CLIENT_ACKNOWLEDGE
+
+
+ DUPS_OK_ACKNOWLEDGE
+
+
+ HornetQ supports two additional modes: PRE_ACKNOWLEDGE and INDIVIDUAL_ACKNOWLEDGE
+ In some cases you can afford
+ to lose messages in event of failure, so it would make sense to acknowledge the message on the
+ server before delivering it to the client.
+ This extra mode is supported by HornetQ and will call it
+ pre-acknowledge mode.
+ The disadvantage of acknowledging on the server before delivery is that the message will be
+ lost if the system crashes after acknowledging the message on the server
+ but before it is delivered to the client. In that case, the message is
+ lost and will not be recovered when the system restart.
+ Depending on your messaging case, pre-acknowledgement mode can avoid
+ extra network traffic and CPU at the cost of coping with message loss.
+ An example of a use case for pre-acknowledgement is for stock price update messages. With
+ these messages it might be reasonable to lose a message in event of crash, since the next
+ price update message will arrive soon, overriding the previous price.
+
+ Please note, that if you use pre-acknowledge mode, then you will lose transactional
+ semantics for messages being consumed, since clearly they are being acknowledged first on
+ the server, not when you commit the transaction. This may be stating the obvious but we
+ like to be clear on these things to avoid confusion!
+
+
+ Using PRE_ACKNOWLEDGE
+ This can be configured in the hornetq-jms.xml file on the connection factory like this:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty-connector"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ <pre-acknowledge>true</pre-acknowledge>
+</connection-factory>
+ Alternatively, to use pre-acknowledgement mode using the JMS API, create a JMS Session
+ with the HornetQSession.PRE_ACKNOWLEDGE constant.
+
+// messages will be acknowledge on the server *before* being delivered to the client
+Session session = connection.createSession(false, HornetQJMSConstants.PRE_ACKNOWLEDGE);
+ Or you can set pre-acknowledge directly on the HornetQConnectionFactory instance using the setter method.
+ To use pre-acknowledgement mode using the core API you can set it directly on the
+ ClientSessionFactory instance using the setter method.
+
+
+ Individual Acknowledge
+ A valid use-case for individual acknowledgement would be when you need to have your own scheduling and you don't know when your message processing will be finished. You should prefer having one consumer per thread worker
+ but this is not possible in some circumstances depending on how complex is your processing. For that you can use the individual Acknowledgement.
+ You basically setup Individual ACK by creating a session with the acknowledge mode with HornetQJMSConstants.INDIVIDUAL_ACKNOWLEDGE. Individual ACK inherits all the semantics from Client Acknowledge,
+ with the exception the message is individually acked.
+
+ Please note, that to avoid confusion on MDB processing, Individual ACKNOWLEDGE is not supported through MDBs (or the inbound resource adapter). this is because you have to finish the process of your message inside the MDB.
+
+
+
+
+ Example
+ See for an example which shows how to use
+ pre-acknowledgement mode with JMS.
+
+
diff --git a/docs/user-manual/en/preface.xml b/docs/user-manual/en/preface.xml
new file mode 100644
index 0000000000..2c1483b3de
--- /dev/null
+++ b/docs/user-manual/en/preface.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Preface
+ What is HornetQ?
+
+
+ HornetQ is an open source project to build a multi-protocol, embeddable, very high
+ performance, clustered, asynchronous messaging system.
+
+
+ HornetQ is an example of Message Oriented Middleware (MoM). For a description of
+ MoMs and other messaging concepts please see the .
+
+
+ For answers to more questions about what HornetQ is and what it isn't please visit
+ the FAQs wiki
+ page.
+
+
+ Why use HornetQ? Here are just a few of the reasons:
+
+
+ 100% open source software. HornetQ is licensed using the Apache Software License v
+ 2.0 to minimise barriers to adoption.
+
+
+ HornetQ is designed with usability in mind.
+
+
+ Written in Java. Runs on any platform with a Java 6+ runtime, that's everything
+ from Windows desktops to IBM mainframes.
+
+
+ Amazing performance. Our ground-breaking high performance journal provides
+ persistent messaging performance at rates normally seen for non-persistent
+ messaging, our non-persistent messaging performance rocks the boat too.
+
+
+ Full feature set. All the features you'd expect in any serious messaging system,
+ and others you won't find anywhere else.
+
+
+ Elegant, clean-cut design with minimal third party dependencies. Run HornetQ
+ stand-alone, run it in integrated in your favourite JEE application server, or run
+ it embedded inside your own product. It's up to you.
+
+
+ Seamless high availability. We provide a HA solution with automatic client
+ failover so you can guarantee zero message loss or duplication in event of server
+ failure.
+
+
+ Hugely flexible clustering. Create clusters of servers that know how to load
+ balance messages. Link geographically distributed clusters over unreliable
+ connections to form a global network. Configure routing of messages in a highly
+ flexible way.
+
+
+ For a full list of features, please see the features wiki
+ page .
+
+
+
diff --git a/docs/user-manual/en/project-info.xml b/docs/user-manual/en/project-info.xml
new file mode 100644
index 0000000000..5bd6ca9b95
--- /dev/null
+++ b/docs/user-manual/en/project-info.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Project Information
+ The official HornetQ project page is http://hornetq.org/.
+
+ Software Download
+ The software can be download from the Download page:http://hornetq.org/downloads.html
+
+
+ Project Information
+
+
+
+ Please take a look at our project wiki
+
+
+ If you have any user questions please use our user
+ forum
+
+
+ If you have development related questions, please use our developer forum
+
+
+ Pop in and chat to us in our IRC channel
+
+
+ Our project blog
+
+
+ Follow us on twitter
+
+
+ HornetQ Git repository is https://github.com/hornetq/hornetq
+
+
+ All release tags are available from https://github.com/hornetq/hornetq/tags
+
+
+
+ Red Hat kindly employs developers to work full time on HornetQ, they are:
+
+ Clebert Suconic (project lead)
+
+
+ Andy Taylor
+
+
+ Howard Gao
+
+
+ Justin Bertram
+
+
+ And many thanks to all our contributors, both old and new who helped create HornetQ,
+ for a full list of the people who made it happen, take a look at our team page.
+
+
diff --git a/docs/user-manual/en/queue-attributes.xml b/docs/user-manual/en/queue-attributes.xml
new file mode 100644
index 0000000000..8ec06b511a
--- /dev/null
+++ b/docs/user-manual/en/queue-attributes.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Queue Attributes
+ Queue attributes can be set in one of two ways. Either by configuring them using the
+ configuration file or by using the core API. This chapter will explain how to configure each
+ attribute and what effect the attribute has.
+
+ Predefined Queues
+ Queues can be predefined via configuration at a core level or at a JMS level. Firstly
+ let's look at a JMS level.
+ The following shows a queue predefined in the hornetq-jms.xml
+ configuration file.
+
+<queue name="selectorQueue">
+ <entry name="/queue/selectorQueue"/>
+ <selector string="color='red'"/>
+ <durable>true</durable>
+</queue>
+ This name attribute of queue defines the name of the queue. When we do this at a jms
+ level we follow a naming convention so the actual name of the core queue will be
+ jms.queue.selectorQueue.
+ The entry element configures the name that will be used to bind the queue to JNDI.
+ This is a mandatory element and the queue can contain multiple of these to bind the same
+ queue to different names.
+ The selector element defines what JMS message selector the predefined queue will have.
+ Only messages that match the selector will be added to the queue. This is an optional
+ element with a default of null when omitted.
+ The durable element specifies whether the queue will be persisted. This again is
+ optional and defaults to true if omitted.
+ Secondly a queue can be predefined at a core level in the hornetq-configuration.xml file. The following is an example.
+
+<queues>
+ <queue name="jms.queue.selectorQueue">
+ <address>jms.queue.selectorQueue</address>
+ <filter string="color='red'"/>
+ <durable>true</durable>
+ </queue>
+</queues>
+ This is very similar to the JMS configuration, with 3 real differences which
+ are.
+
+
+ The name attribute of queue is the actual name used for the queue with no
+ naming convention as in JMS.
+
+
+ The address element defines what address is used for routing messages.
+
+
+ There is no entry element.
+
+
+ The filter uses the Core filter syntax (described in
+ ), not the JMS
+ selector syntax.
+
+
+
+
+ Using the API
+ Queues can also be created using the core API or the management API.
+ For the core API, queues can be created via the org.hornetq.api.core.client.ClientSession interface. There are multiple
+ createQueue methods that support setting all of the previously
+ mentioned attributes. There is one extra attribute that can be set via this API which is
+ temporary. setting this to true means that the queue will be
+ deleted once the session is disconnected.
+ Take a look at for a description of the management API
+ for creating queues.
+
+
+ Configuring Queues Via Address Settings
+ There are some attributes that are defined against an address wildcard rather than a
+ specific queue. Here an example of an address-setting entry that
+ would be found in the hornetq-configuration.xml file.
+
+<address-settings>
+ <address-setting match="jms.queue.exampleQueue">
+ <dead-letter-address>jms.queue.deadLetterQueue</dead-letter-address>
+ <max-delivery-attempts>3</max-delivery-attempts>
+ <redelivery-delay>5000</redelivery-delay>
+ <expiry-address>jms.queue.expiryQueue</expiry-address>
+ <last-value-queue>true</last-value-queue>
+ <max-size-bytes>100000</max-size-bytes>
+ <page-size-bytes>20000</page-size-bytes>
+ <redistribution-delay>0</redistribution-delay>
+ <send-to-dla-on-no-route>true</send-to-dla-on-no-route>
+ <address-full-policy>PAGE</address-full-policy>
+ </address-setting>
+</address-settings>
+ The idea with address settings, is you can provide a block of settings which will be
+ applied against any addresses that match the string in the match attribute. In the
+ above example the settings would only be applied to any addresses which exactly match
+ the address jms.queue.exampleQueue, but you can also use wildcards to apply sets of
+ configuration against many addresses. The wildcard syntax used is described here.
+ For example, if you used the match string jms.queue.# the settings would be applied
+ to all addresses which start with jms.queue. which would be all JMS queues.
+ The meaning of the specific settings are explained fully throughout the user manual, however here is a brief
+ description with a link to the appropriate chapter if available.
+ max-delivery-attempts defines how many time a cancelled message can
+ be redelivered before sending to the dead-letter-address. A full
+ explanation can be found here.
+ redelivery-delay defines how long to wait before attempting
+ redelivery of a cancelled message. see here.
+ expiry-address defines where to send a message that has expired.
+ see here.
+ expiry-delay defines the expiration time that will be used for messages which are using
+ the default expiration time (i.e. 0). For example, if expiry-delay is set to "10" and a
+ message which is using the default expiration time (i.e. 0) arrives then its expiration time of "0" will be
+ changed to "10." However, if a message which is using an expiration time of "20" arrives then its expiration
+ time will remain unchanged. Setting expiry-delay to "-1" will disable this feature. The
+ default is "-1".
+ last-value-queue defines whether a queue only uses last values or
+ not. see here.
+ max-size-bytes and page-size-bytes are used to
+ set paging on an address. This is explained here.
+ redistribution-delay defines how long to wait when the last
+ consumer is closed on a queue before redistributing any messages. see here.
+ send-to-dla-on-no-route. If a message is sent to an address, but the server does not route it to any queues,
+ for example, there might be no queues bound to that address, or none of the queues have filters that match, then normally that message
+ would be discarded. However if this parameter is set to true for that address, if the message is not routed to any queues it will instead
+ be sent to the dead letter address (DLA) for that address, if it exists.
+ address-full-policy. This attribute can have one of the following values: PAGE, DROP, FAIL or BLOCK and determines what happens when
+ an address where max-size-bytes is specified becomes full. The default value is PAGE. If the value is PAGE then further messages will be paged to disk.
+ If the value is DROP then further messages will be silently dropped.
+ If the value is FAIL then further messages will be dropped and an exception will be thrown on the client-side.
+ If the value is BLOCK then client message producers will block when they try and send further messages.
+
+ See the following chapters for more info , .
+
+
+
+
+
diff --git a/docs/user-manual/en/rest.xml b/docs/user-manual/en/rest.xml
new file mode 100644
index 0000000000..ae5c416eff
--- /dev/null
+++ b/docs/user-manual/en/rest.xml
@@ -0,0 +1,2151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ REST Interface
+
+ The HornetQ REST interface allows you to leverage the reliability
+ and scalability features of HornetQ over a simple REST/HTTP interface.
+ Messages are produced and consumed by sending and receiving simple HTTP
+ messages that contain the content you want to push around. For instance,
+ here's a simple example of posting an order to an order processing queue
+ express as an HTTP message:
+
+
+
+POST /queue/orders/create HTTP/1.1
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Bill</name>
+ <item>iPhone 4</item>
+ <cost>$199.99</cost>
+</order>
+
+ As you can see, we're just posting some arbitrary XML
+ document to a URL. When the XML is received on the server is it processed
+ within HornetQ as a JMS message and distributed through core HornetQ.
+ Simple and easy. Consuming messages from a queue or topic looks very
+ similar. We'll discuss the entire interface in detail later in this
+ docbook.
+
+
+
+ Goals of REST Interface
+
+ Why would you want to use HornetQ's REST interface? What are the
+ goals of the REST interface?
+
+
+
+
+ Easily usable by machine-based (code) clients.
+
+
+
+ Zero client footprint. We want HornetQ to be usable by any
+ client/programming language that has an adequate HTTP client
+ library. You shouldn't have to download, install, and configure a
+ special library to interact with HornetQ.
+
+
+
+
+ Lightweight interoperability. The HTTP protocol is strong
+ enough to be our message exchange protocol. Since interactions are
+ RESTful the HTTP uniform interface provides all the interoperability
+ you need to communicate between different languages, platforms, and
+ even messaging implementations that choose to implement the same
+ RESTful interface as HornetQ (i.e. the
+ REST-* effort.)
+
+
+
+
+ No envelope (e.g. SOAP) or feed (e.g. Atom) format
+ requirements. You shouldn't have to learn, use, or parse a specific
+ XML document format in order to send and receive messages through
+ HornetQ's REST interface.
+
+
+
+
+ Leverage the reliability, scalability, and clustering features
+ of HornetQ on the back end without sacrificing the simplicity of a
+ REST interface.
+
+
+
+
+
+
+
+ Installation and Configuration
+
+ HornetQ's REST interface is installed as a Web archive (WAR). It
+ depends on the
+ RESTEasy
+ project and can currently only run within a servlet container. Installing
+ the HornetQ REST interface is a little bit different depending whether
+ HornetQ is already installed and configured for your environment (e.g.
+ you're deploying within JBoss AS 7) or you want the HornetQ REST
+ WAR to startup and manage the HornetQ server (e.g. you're deploying
+ within something like Apache Tomcat).
+
+
+
+ Installing Within Pre-configured Environment
+
+ This section should be used when you want to use the HornetQ REST
+ interface in an environment that already has HornetQ installed and
+ running, e.g. JBoss AS 7. You must create a Web archive
+ (.WAR) file with the following web.xml settings:
+
+
+
+<web-app>
+ <listener>
+ <listener-class>
+ org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
+ </listener-class>
+ </listener>
+
+ <listener>
+ <listener-class>
+ org.hornetq.rest.integration.RestMessagingBootstrapListener
+ </listener-class>
+ </listener>
+
+ <filter>
+ <filter-name>Rest-Messaging</filter-name>
+ <filter-class>
+ org.jboss.resteasy.plugins.server.servlet.FilterDispatcher
+ </filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Rest-Messaging</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+</web-app>
+
+ Within your WEB-INF/lib directory you must have the
+ hornetq-rest.jar file. If RESTEasy is not installed within your
+ environment, you must add the RESTEasy jar files within the lib
+ directory as well. Here's a sample Maven pom.xml that can build your WAR
+ for this case.
+
+
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.somebody</groupId>
+ <artifactId>myapp</artifactId>
+ <packaging>war</packaging>
+ <name>My App</name>
+ <version>0.1-SNAPSHOT</version>
+ <repositories>
+ <repository>
+ <id>jboss</id>
+ <url>http://repository.jboss.org/nexus/content/groups/public/</url>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.hornetq.rest</groupId>
+ <artifactId>hornetq-rest</artifactId>
+ <version>2.3.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
+
+
+ JBoss AS 7 loads classes differently than previous versions.
+ To work properly in AS 7 the WAR will need this in its MANIFEST.MF:
+
+ Dependencies: org.hornetq, org.jboss.netty
+ You can add this to the<plugins>
+ section of the pom.xml to create this entry automatically:
+
+
+<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Dependencies>org.hornetq, org.jboss.netty</Dependencies>
+ </manifestEntries>
+ </archive>
+ </configuration>
+</plugin>
+
+
+
+ It is worth noting that when deploying a WAR in a Java EE application server
+ like AS7 the URL for the resulting application will include the name of the
+ WAR by default. For example, if you've constructed a WAR as described above
+ named "hornetq-rest.war" then clients will access it at, e.g.
+ http://localhost:8080/hornetq-rest/[queues|topics]. We'll see more about
+ this later.
+
+
+
+ It is possible to put the WAR file at the "root context" of AS7, but
+ that is beyond the scope of this documentation.
+
+
+
+
+
+ Bootstrapping HornetQ Along with REST
+
+ You can bootstrap HornetQ within your WAR as well. To do this, you
+ must have the HornetQ core and JMS jars along with Netty, Resteasy, and
+ the HornetQ REST jar within your WEB-INF/lib. You must also have a
+ hornetq-configuration.xml, hornetq-jms.xml, and hornetq-users.xml config
+ files within WEB-INF/classes. The examples that come with the HornetQ
+ REST distribution show how to do this. You must also add an additional
+ listener to your web.xml file. Here's an example:
+
+
+
+<web-app>
+ <listener>
+ <listener-class>
+ org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
+ </listener-class>
+ </listener>
+
+ <listener>
+ <listener-class>
+ org.hornetq.rest.integration.HornetqBootstrapListener
+ </listener-class>
+ </listener>
+
+ <listener>
+ <listener-class>
+ org.hornetq.rest.integration.RestMessagingBootstrapListener
+ </listener-class>
+ </listener>
+
+ <filter>
+ <filter-name>Rest-Messaging</filter-name>
+ <filter-class>
+ org.jboss.resteasy.plugins.server.servlet.FilterDispatcher
+ </filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Rest-Messaging</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+</web-app>
+
+ Here's a Maven pom.xml file for creating a WAR for this
+ environment. Make sure your hornetq configuration files are within the
+ src/main/resources directory so that they are stuffed within the WAR's
+ WEB-INF/classes directory!
+
+
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.somebody</groupId>
+ <artifactId>myapp</artifactId>
+ <packaging>war</packaging>
+ <name>My App</name>
+ <version>0.1-SNAPSHOT</version>
+ <repositories>
+ <repository>
+ <id>jboss</id>
+ <url>http://repository.jboss.org/nexus/content/groups/public/</url>
+ </repository>
+ </repositories>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.hornetq</groupId>
+ <artifactId>hornetq-core</artifactId>
+ <version>2.3.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty</artifactId>
+ <version>3.4.5.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hornetq</groupId>
+ <artifactId>hornetq-jms</artifactId>
+ <version>2.3.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.jms</groupId>
+ <artifactId>jboss-jms-api_2.0_spec</artifactId>
+ <version>1.0.0.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hornetq.rest</groupId>
+ <artifactId>hornetq-rest</artifactId>
+ <version>2.3.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>2.3.4.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxb-provider</artifactId>
+ <version>2.3.4.Final</version>
+ </dependency>
+ </dependencies>
+</project>
+
+
+
+ REST Configuration
+
+ The HornetQ REST implementation does have some configuration
+ options. These are configured via XML configuration file that must be in
+ your WEB-INF/classes directory. You must set the web.xml context-param
+ rest.messaging.config.file to specify the name of the
+ configuration file. Below is the format of the XML configuration file
+ and the default values for each.
+
+
+
+<rest-messaging>
+ <server-in-vm-id>0</server-in-vm-id>
+ <use-link-headers>false</use-link-headers>
+ <default-durable-send>false</default-durable-send>
+ <dups-ok>true</dups-ok>
+ <topic-push-store-dir>topic-push-store</topic-push-store-dir>
+ <queue-push-store-dir>queue-push-store</queue-push-store-dir>
+ <producer-time-to-live>0</producer-time-to-live>
+ <producer-session-pool-size>10</producer-session-pool-size>
+ <session-timeout-task-interval>1</session-timeout-task-interval>
+ <consumer-session-timeout-seconds>300</consumer-session-timeout-seconds>
+ <consumer-window-size>-1</consumer-window-size>
+</rest-messaging>
+
+ Let's give an explanation of each config option.
+
+
+
+ server-in-vm-id. The HornetQ REST
+ impl uses the IN-VM transport to communicate with HornetQ.
+ It uses the default server id, which is "0".
+
+
+
+ use-link-headers. By default, all
+ links (URLs) are published using custom headers. You can
+ instead have the HornetQ REST implementation publish links
+ using the
+ Link Header specification
+ instead if you desire.
+
+
+
+ default-durable-send. Whether a posted
+ message should be persisted by default if the user does not
+ specify a durable query parameter.
+
+
+
+ dups-ok. If this is true, no duplicate
+ detection protocol will be enforced for message posting.
+
+
+
+ topic-push-store-dir. This must be
+ a relative or absolute file system path. This is a directory
+ where push registrations for topics are stored. See
+ Pushing Messages.
+
+
+
+ queue-push-store-dir. This must be
+ a relative or absolute file system path. This is a
+ directory where push registrations for queues are stored.
+ See Pushing Messages.
+
+
+
+ producer-session-pool-size. The REST
+ implementation pools HornetQ sessions for sending messages.
+ This is the size of the pool. That number of sessions will
+ be created at startup time.
+
+
+
+ producer-time-to-live. Default time
+ to live for posted messages. Default is no ttl.
+
+
+
+ session-timeout-task-interval. Pull
+ consumers and pull subscriptions can time out. This is
+ the interval the thread that checks for timed-out sessions
+ will run at. A value of 1 means it will run every 1 second.
+
+
+
+ consumer-session-timeout-seconds.
+ Timeout in seconds for pull consumers/subscriptions that
+ remain idle for that amount of time.
+
+
+
+ consumer-window-size. For consumers,
+ this config option is the same as the HornetQ one of the
+ same name. It will be used by sessions created by the
+ HornetQ REST implementation.
+
+
+
+
+
+
+
+
+ HornetQ REST Interface Basics
+
+ The HornetQ REST interface publishes a variety of REST resources to
+ perform various tasks on a queue or topic. Only the top-level queue and
+ topic URI schemes are published to the outside world. You must discover
+ all over resources to interact with by looking for and traversing links.
+ You'll find published links within custom response headers and embedded in
+ published XML representations. Let's look at how this works.
+
+
+
+ Queue and Topic Resources
+
+ To interact with a queue or topic you do a HEAD or GET request on
+ the following relative URI pattern:
+
+
+
+/queues/{name}
+/topics/{name}
+
+ The base of the URI is the base URL of the WAR you deployed the
+ HornetQ REST server within as defined in the
+ Installation and Configuration
+ section of this document. Replace the {name}
+ string within the above URI pattern with the name of the queue or
+ topic you are interested in interacting with. For example if you
+ have configured a JMS topic named "foo" within your
+ hornetq-jms.xml file, the URI name should be
+ "jms.topic.foo". If you have configured a JMS queue name "bar" within
+ your hornetq-jms.xml file, the URI name should be
+ "jms.queue.bar". Internally, HornetQ prepends the "jms.topic" or
+ "jms.queue" strings to the name of the deployed destination. Next,
+ perform your HEAD or GET request on this URI. Here's what a
+ request/response would look like.
+
+
+
+HEAD /queues/jms.queue.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/queues/jms.queue.bar/create
+msg-create-with-id: http://example.com/queues/jms.queue.bar/create/{id}
+msg-pull-consumers: http://example.com/queues/jms.queue.bar/pull-consumers
+msg-push-consumers: http://example.com/queues/jms.queue.bar/push-consumers
+
+
+
+ You can use the "curl" utility to test this easily. Simply execute
+ a command like this:
+
+
+
+curl --head http://example.com/queues/jms.queue.bar
+
+
+ The HEAD or GET response contains a number of custom response
+ headers that are URLs to additional REST resources that allow you to
+ interact with the queue or topic in different ways. It is important not
+ to rely on the scheme of the URLs returned within these headers as they
+ are an implementation detail. Treat them as opaque and query for them
+ each and every time you initially interact (at boot time) with the
+ server. If you treat all URLs as opaque then you will be isolated from
+ implementation changes as the HornetQ REST interface evolves over
+ time.
+
+
+
+
+ Queue Resource Response Headers
+
+ Below is a list of response headers you should expect when
+ interacting with a Queue resource.
+
+
+
+
+ msg-create. This is a URL you POST messages
+ to. The semantics of this link are described in
+ Posting Messages.
+
+
+
+ msg-create-with-id. This is a URL
+ template you can use to POST messages.
+ The semantics of this link are described in
+ Posting Messages.
+
+
+
+ msg-pull-consumers. This is a URL for
+ creating consumers that will pull from a queue. The semantics
+ of this link are described in
+ Consuming Messages via Pull.
+
+
+
+ msg-push-consumers. This is a URL for
+ registering other URLs you want the HornetQ REST server to
+ push messages to. The semantics of this link are described
+ in Pushing Messages.
+
+
+
+
+
+
+ Topic Resource Response Headers
+
+ Below is a list of response headers you should expect when
+ interacting with a Topic resource.
+
+
+
+
+ msg-create. This is a URL you POST
+ messages to. The semantics of this link are described in
+ Posting Messages.
+
+
+
+ msg-create-with-id. This is a URL
+ template you can use to POST messages.
+ The semantics of this link are described in
+ Posting Messages.
+
+
+
+ msg-pull-subscriptions. This is a
+ URL for creating subscribers that will pull from a topic.
+ The semantics of this link are described in
+ Consuming Messages via Pull.
+
+
+
+ msg-push-subscriptions. This is a
+ URL for registering other URLs you want the HornetQ REST
+ server to push messages to. The semantics of this link
+ are described in Pushing
+ Messages.
+
+
+
+
+
+
+
+
+ Posting Messages
+
+ This chapter discusses the protocol for posting messages to a queue
+ or a topic. In HornetQ REST Interface Basics,
+ you saw that a queue or topic resource publishes variable custom headers
+ that are links to other RESTful resources. The msg-create
+ header is a URL you can post a message to. Messages are published to a queue
+ or topic by sending a simple HTTP message to the URL published by the
+ msg-create header. The HTTP message contains whatever
+ content you want to publish to the HornetQ destination. Here's an example
+ scenario:
+
+
+
+ You can also post messages to the URL template found in
+ msg-create-with-id, but this is a more advanced
+ use-case involving duplicate detection that we will discuss later in
+ this section.
+
+
+
+
+
+ Obtain the starting msg-create header from
+ the queue or topic resource.
+
+
+
+
+HEAD /queues/jms.queue.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/queues/jms.queue.bar/create
+msg-create-with-id: http://example.com/queues/jms.queue.bar/create/{id}
+
+
+
+
+ Do a POST to the URL contained in the msg-create
+ header.
+
+
+
+POST /queues/jms.queue.bar/create
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Bill</name>
+ <item>iPhone4</name>
+ <cost>$199.99</cost>
+</order>
+
+--- Response ---
+HTTP/1.1 201 Created
+msg-create-next: http://example.com/queues/jms.queue.bar/create
+
+
+ You can use the "curl" utility to test this easily. Simply execute
+ a command like this:
+
+
+curl --verbose --data "123" http://example.com/queues/jms.queue.bar/create
+
+
+ A successful response will return a 201 response code. Also
+ notice that a msg-create-next response header
+ is sent as well. You must use this URL to POST your next message.
+
+
+
+
+ POST your next message to the queue using the URL returned in
+ the msg-create-next header.
+
+
+
+POST /queues/jms.queue.bar/create
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Monica</name>
+ <item>iPad</item>
+ <cost>$499.99</cost>
+</order>
+
+--- Response --
+HTTP/1.1 201 Created
+msg-create-next: http://example.com/queues/jms.queue.bar/create
+ Continue using the new msg-create-next
+ header returned with each response.
+
+
+
+
+
+ It is VERY IMPORTANT that you never re-use returned
+ msg-create-next headers to post new messages. If the
+ dups-ok configuration property is set to
+ false on the server then this URL will be uniquely
+ generated for each message and used for duplicate detection. If you lose
+ the URL within the msg-create-next header, then just
+ go back to the queue or topic resource to get the
+ msg-create URL again.
+
+
+
+
+ Duplicate Detection
+
+ Sometimes you might have network problems when posting new
+ messages to a queue or topic. You may do a POST and never receive a
+ response. Unfortunately, you don't know whether or not the server
+ received the message and so a re-post of the message might cause
+ duplicates to be posted to the queue or topic. By default, the HornetQ
+ REST interface is configured to accept and post duplicate messages. You
+ can change this by turning on duplicate message detection by setting the
+ dups-ok config option to false
+ as described in HornetQ REST Interface Basics.
+ When you do this, the initial POST to the msg-create
+ URL will redirect you, using the standard HTTP 307 redirection mechanism
+ to a unique URL to POST to. All other interactions remain the same as
+ discussed earlier. Here's an example:
+
+
+
+
+ Obtain the starting msg-create header from
+ the queue or topic resource.
+
+
+
+
+HEAD /queues/jms.queue.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/queues/jms.queue.bar/create
+msg-create-with-id: http://example.com/queues/jms.queue.bar/create/{id}
+
+
+
+
+ Do a POST to the URL contained in the msg-create
+ header.
+
+
+
+POST /queues/jms.queue.bar/create
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Bill</name>
+ <item>iPhone4</name>
+ <cost>$199.99</cost>
+</order>
+
+--- Response ---
+HTTP/1.1 307 Redirect
+Location: http://example.com/queues/jms.queue.bar/create/13582001787372
+
+ A successful response will return a 307 response code. This
+ is standard HTTP protocol. It is telling you that you must re-POST
+ to the URL contained within the Location
+ header.
+
+
+
+
+ re-POST your message to the URL provided within the
+ Location header.
+
+
+
+POST /queues/jms.queue.bar/create/13582001787372
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Bill</name>
+ <item>iPhone4</name>
+ <cost>$199.99</cost>
+</order>
+
+--- Response --
+HTTP/1.1 201 Created
+msg-create-next: http://example.com/queues/jms.queue.bar/create/13582001787373
+ You should receive a 201 Created response. If there is a
+ network failure, just re-POST to the Location header. For new
+ messages, use the returned msg-create-next
+ header returned with each response.
+
+
+
+
+ POST any new message to the returned
+ msg-create-next header.
+
+
+
+POST /queues/jms.queue.bar/create/13582001787373
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Monica</name>
+ <item>iPad</name>
+ <cost>$499.99</cost>
+</order>
+
+--- Response --
+HTTP/1.1 201 Created
+msg-create-next: http://example.com/queues/jms.queue.bar/create/13582001787374
+ If there ever is a network problem, just repost to the URL
+ provided in the msg-create-next header.
+
+
+
+
+ How can this work? As you can see, with each successful response,
+ the HornetQ REST server returns a uniquely generated URL within the
+ msg-create-next header. This URL is dedicated to the next new message
+ you want to post. Behind the scenes, the code extracts an identify from
+ the URL and uses HornetQ's duplicate detection mechanism by setting the
+ DUPLICATE_DETECTION_ID property of the JMS message
+ that is actually posted to the system.
+
+
+ If you happen to use the same ID more than once you'll see a message
+ like this on the server:
+
+
+WARN [org.hornetq.core.server] (Thread-3 (HornetQ-remoting-threads-HornetQServerImpl::serverUUID=8d6be6f8-5e8b-11e2-80db-51bbde66f473-26319292-267207)) HQ112098: Duplicate message detected - message will not be routed. Message information:
+ServerMessage[messageID=20,priority=4, bodySize=1500,expiration=0, durable=true, address=jms.queue.bar,properties=TypedProperties[{http_content$type=application/x-www-form-urlencoded, http_content$length=3, postedAsHttpMessage=true, _HQ_DUPL_ID=42}]]@12835058
+
+ An alternative to this approach is to use the msg-create-with-id
+ header. This is not an invokable URL, but a URL template. The idea is that
+ the client provides the DUPLICATE_DETECTION_ID and creates
+ its own create-next URL. The msg-create-with-id
+ header looks like this (you've see it in previous examples, but we haven't used it):
+
+
+
+msg-create-with-id: http://example.com/queues/jms.queue.bar/create/{id}
+
+ You see that it is a regular URL appended with a {id}. This
+ {id} is a pattern matching substring. A client would generate its
+ DUPLICATE_DETECTION_ID and replace {id}
+ with that generated id, then POST to the new URL. The URL the client creates
+ works exactly like a create-next URL described earlier. The
+ response of this POST would also return a new msg-create-next
+ header. The client can continue to generate its own DUPLICATE_DETECTION_ID, or
+ use the new URL returned via the msg-create-next header.
+
+
+ The advantage of this approach is that the client does not have to
+ repost the message. It also only has to come up with a unique
+ DUPLICATE_DETECTION_ID once.
+
+
+
+
+ Persistent Messages
+
+ By default, posted messages are not durable and will not be
+ persisted in HornetQ's journal. You can create durable messages by
+ modifying the default configuration as expressed in Chapter 2 so that
+ all messages are persisted when sent. Alternatively, you can set a URL
+ query parameter called durable to true when you post
+ your messages to the URLs returned in the msg-create,
+ msg-create-with-id, or msg-create-next
+ headers. here's an example of that.
+
+
+
+POST /queues/jms.queue.bar/create?durable=true
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Bill</name>
+ <item>iPhone4</item>
+ <cost>$199.99</cost>
+</order>
+
+
+
+ TTL, Expiration and Priority
+
+ You can set the time to live, expiration, and/or the priority of
+ the message in the queue or topic by setting an additional query
+ parameter. The expiration query parameter is an long
+ specify the time in milliseconds since epoch (a long date). The
+ ttl query parameter is a time in milliseconds you
+ want the message active. The priority is another
+ query parameter with an integer value between 0 and 9 expressing the
+ priority of the message. i.e.:
+
+
+
+POST /queues/jms.queue.bar/create?expiration=30000&priority=3
+Host: example.com
+Content-Type: application/xml
+
+<order>
+ <name>Bill</name>
+ <item>iPhone4</item>
+ <cost>$199.99</cost>
+</order>
+
+
+
+
+ Consuming Messages via Pull
+
+ There are two different ways to consume messages from a topic or
+ queue. You can wait and have the messaging server push them to you, or you
+ can continuously poll the server yourself to see if messages are
+ available. This chapter discusses the latter. Consuming messages via a
+ pull works almost identically for queues and topics with some minor, but
+ important caveats. To start consuming you must create a consumer resource
+ on the server that is dedicated to your client. Now, this pretty much
+ breaks the stateless principle of REST, but after much prototyping, this
+ is the best way to work most effectively with HornetQ through a REST
+ interface.
+
+
+ You create consumer resources by doing a simple POST to the URL
+ published by the msg-pull-consumers
+ response header if you are interacting with a queue, the
+ msg-pull-subscribers response header if you're
+ interacting with a topic. These headers are provided by the main queue or
+ topic resource discussed in HornetQ REST Interface
+ Basics. Doing an empty POST to one of these
+ URLs will create a consumer resource that follows an auto-acknowledge
+ protocol and, if you are interacting with a topic, creates a temporarily
+ subscription to the topic. If you want to use the acknowledgement protocol
+ and/or create a durable subscription (topics only), then you must use the
+ form parameters (application/x-www-form-urlencoded)
+ described below.
+
+
+
+
+ autoAck. A value of true
+ or false can be given. This defaults to
+ true if you do not pass this parameter.
+
+
+
+ durable. A value of true
+ or false can be given. This defaults to
+ false if you do not pass this parameter.
+ Only available on topics. This specifies whether you want a
+ durable subscription or not. A durable subscription persists
+ through server restart.
+
+
+
+ name. This is the name of the durable
+ subscription. If you do not provide this parameter, the name
+ will be automatically generated by the server. Only usable
+ on topics.
+
+
+
+ selector. This is an optional JMS selector
+ string. The HornetQ REST interface adds HTTP headers to the
+ JMS message for REST produced messages. HTTP headers are
+ prefixed with "http_" and every '-' character is converted
+ to a '$'.
+
+
+
+ idle-timeout. For a topic subscription,
+ idle time in milliseconds in which the consumer connections
+ will be closed if idle.
+
+
+
+ delete-when-idle. Boolean value, If
+ true, a topic subscription will be deleted (even if it is
+ durable) when an the idle timeout is reached.
+
+
+
+
+
+ If you have multiple pull-consumers active at the same time
+ on the same destination be aware that unless the
+ consumer-window-size is 0 then one consumer
+ might buffer messages while the other consumer gets none.
+
+
+
+
+ Auto-Acknowledge
+
+ This section focuses on the auto-acknowledge protocol for
+ consuming messages via a pull. Here's a list of the response
+ headers and URLs you'll be interested in.
+
+
+
+
+ msg-pull-consumers. The URL of
+ a factory resource for creating queue consumer
+ resources. You will pull from these created resources.
+
+
+
+ msg-pull-subscriptions. The URL
+ of a factory resource for creating topic subscription
+ resources. You will pull from the created resources.
+
+
+
+ msg-consume-next. The URL you
+ will pull the next message from. This is returned
+ with every response.
+
+
+
+ msg-consumer. This is a URL
+ pointing back to the consumer or subscription
+ resource created for the client.
+
+
+
+
+
+ Creating an Auto-Ack Consumer or Subscription
+
+ Here is an example of creating an auto-acknowledged
+ queue pull consumer.
+
+
+
+
+ Find the pull-consumers URL by doing a HEAD or
+ GET request to the base queue resource.
+
+
+
+HEAD /queues/jms.queue.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/queues/jms.queue.bar/create
+msg-pull-consumers: http://example.com/queues/jms.queue.bar/pull-consumers
+msg-push-consumers: http://example.com/queues/jms.queue.bar/push-consumers
+
+
+
+ Next do an empty POST to the URL returned in the
+ msg-pull-consumers
+ header.
+
+
+
+POST /queues/jms.queue.bar/pull-consumers HTTP/1.1
+Host: example.com
+
+--- response ---
+HTTP/1.1 201 Created
+Location: http://example.com/queues/jms.queue.bar/pull-consumers/auto-ack/333
+msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/auto-ack/333/consume-next-1
+
+ The
+ Location
+ header points to the JMS
+ consumer resource that was created on the server. It is good to
+ remember this URL, although, as you'll see later, it is
+ transmitted with each response just to remind you.
+
+
+
+
+ Creating an auto-acknowledged consumer for a topic is pretty
+ much the same. Here's an example of creating a durable
+ auto-acknowledged topic pull subscription.
+
+
+
+
+ Find the
+ pull-subscriptions
+ URL by doing
+ a HEAD or GET request to the base topic resource
+
+
+
+HEAD /topics/jms.topic.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/topics/jms.topic.foo/create
+msg-pull-subscriptions: http://example.com/topics/jms.topic.foo/pull-subscriptions
+msg-push-subscriptions: http://example.com/topics/jms.topic.foo/push-subscriptions
+
+
+
+ Next do a POST to the URL returned in the
+ msg-pull-subscriptions
+ header passing in a true
+ value for the durable
+ form parameter.
+
+
+
+POST /topics/jms.topic.foo/pull-subscriptions HTTP/1.1
+Host: example.com
+Content-Type: application/x-www-form-urlencoded
+
+durable=true
+
+--- Response ---
+HTTP/1.1 201 Created
+Location: http://example.com/topics/jms.topic.foo/pull-subscriptions/auto-ack/222
+msg-consume-next:
+http://example.com/topics/jms.topic.foo/pull-subscriptions/auto-ack/222/consume-next-1
+
+ The
+ Location
+ header points to the JMS
+ subscription resource that was created on the server. It is good
+ to remember this URL, although, as you'll see later, it is
+ transmitted with each response just to remind you.
+
+
+
+
+
+
+ Consuming Messages
+
+ After you have created a consumer resource, you are ready to
+ start pulling messages from the server. Notice that when you created
+ the consumer for either the queue or topic, the response contained a
+ msg-consume-next response header. POST to the URL
+ contained within this header to consume the next message in the queue
+ or topic subscription. A successful POST causes the server to extract
+ a message from the queue or topic subscription, acknowledge it, and
+ return it to the consuming client. If there are no messages in the
+ queue or topic subscription, a 503 (Service Unavailable) HTTP code is
+ returned.
+
+
+
+ For both successful and unsuccessful posts to the
+ msg-consume-next URL, the response will contain a new
+ msg-consume-next header. You must ALWAYS use this new URL returned
+ within the new msg-consume-next header to consume new
+ messages.
+
+
+
+ Here's an example of pulling multiple messages from the consumer
+ resource.
+
+
+
+
+ Do a POST on the msg-consume-next URL that was returned with
+ the consumer or subscription resource discussed earlier.
+
+
+
+POST /queues/jms.queue.bar/pull-consumers/consume-next-1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+Content-Type: application/xml
+msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-2
+msg-consumer: http://example.com/queues/jms.queue.bar/pull-consumers/333
+
+<order>...</order>
+
+ The POST returns the message consumed from the queue. It
+ also returns a new msg-consume-next link. Use this new link to get
+ the next message. Notice also a msg-consumer response header is
+ returned. This is a URL that points back to the consumer or
+ subscription resource. You will need that to clean up your
+ connection after you are finished using the queue or topic.
+
+
+
+
+ The POST returns the message consumed from the queue. It
+ also returns a new msg-consume-next link. Use this new link to get
+ the next message.
+
+
+
+POST /queues/jms.queue.bar/pull-consumers/consume-next-2
+Host: example.com
+
+--- Response ---
+Http/1.1 503 Service Unavailable
+Retry-After: 5
+msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-2
+
+ In this case, there are no messages in the queue, so we get
+ a 503 response back. As per the HTTP 1.1 spec, a 503 response may
+ return a Retry-After head specifying the time in seconds that you
+ should retry a post. Also notice, that another new
+ msg-consume-next URL is present. Although it probably is the same
+ URL you used last post, get in the habit of using URLs returned in
+ response headers as future versions of HornetQ REST might be
+ redirecting you or adding additional data to the URL after
+ timeouts like this.
+
+
+
+
+ POST to the URL within the last
+ msg-consume-next
+ to get the next
+ message.
+
+
+
+POST /queues/jms.queue.bar/pull-consumers/consume-next-2
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+Content-Type: application/xml
+msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-3
+
+<order>...</order>
+
+
+
+
+
+ Recovering From Network Failures
+
+ If you experience a network failure and do not know if your post
+ to a msg-consume-next URL was successful or not, just re-do your POST.
+ A POST to a msg-consume-next URL is idempotent, meaning that it will
+ return the same result if you execute on any one msg-consume-next URL
+ more than once. Behind the scenes, the consumer resource caches the
+ last consumed message so that if there is a message failure and you do
+ a re-post, the cached last message will be returned (along with a new
+ msg-consume-next URL). This is the reason why the protocol always
+ requires you to use the next new msg-consume-next URL returned with
+ each response. Information about what state the client is in is
+ embedded within the actual URL.
+
+
+
+
+ Recovering From Client or Server Crashes
+
+ If the server crashes and you do a POST to the msg-consume-next
+ URL, the server will return a 412 (Preconditions Failed) response
+ code. This is telling you that the URL you are using is out of sync
+ with the server. The response will contain a new msg-consume-next
+ header to invoke on.
+
+
+ If the client crashes there are multiple ways you can recover.
+ If you have remembered the last msg-consume-next link, you can just
+ re-POST to it. If you have remembered the consumer resource URL, you
+ can do a GET or HEAD request to obtain a new msg-consume-next URL. If
+ you have created a topic subscription using the name parameter
+ discussed earlier, you can re-create the consumer. Re-creation will
+ return a msg-consume-next URL you can use. If you cannot do any of
+ these things, you will have to create a new consumer.
+
+
+ The problem with the auto-acknowledge protocol is that if the
+ client or server crashes, it is possible for you to skip messages. The
+ scenario would happen if the server crashes after auto-acknowledging a
+ message and before the client receives the message. If you want more
+ reliable messaging, then you must use the acknowledgement
+ protocol.
+
+
+
+
+
+ Manual Acknowledgement
+
+ The manual acknowledgement protocol is similar to the auto-ack
+ protocol except there is an additional round trip to the server to tell
+ it that you have received the message and that the server can internally
+ ack the message. Here is a list of the response headers you will be
+ interested in.
+
+
+
+
+ msg-pull-consumers. The URL of a factory resource for creating queue
+ consumer
+ resources. You will pull from these created resources
+
+
+
+ msg-pull-subscriptions. The URL of a factory resource for creating topic
+ subscription resources. You will pull from the created
+ resources.
+
+
+
+ msg-acknowledge-next. URL used to obtain the next message in the queue or
+ topic
+ subscription. It does not acknowledge the message though.
+
+
+
+ msg-acknowledgement. URL used to acknowledge a message.
+
+
+
+ msg-consumer. This is a URL pointing back to the consumer or subscription
+ resource created for the client.
+
+
+
+
+
+ Creating manually-acknowledged consumers or
+ subscriptions
+
+
+ Here is an example of creating an auto-acknowledged queue pull
+ consumer.
+
+
+
+
+ Find the pull-consumers URL by doing a HEAD or GET request
+ to the base queue resource.
+
+
+
+HEAD /queues/jms.queue.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/queues/jms.queue.bar/create
+msg-pull-consumers: http://example.com/queues/jms.queue.bar/pull-consumers
+msg-push-consumers: http://example.com/queues/jms.queue.bar/push-consumers
+
+
+
+ Next do a POST to the URL returned in the
+ msg-pull-consumers
+ header passing in a
+ false
+ value to the
+ autoAck
+ form parameter .
+
+
+
+POST /queues/jms.queue.bar/pull-consumers HTTP/1.1
+Host: example.com
+Content-Type: application/x-www-form-urlencoded
+
+autoAck=false
+
+--- response ---
+HTTP/1.1 201 Created
+Location: http://example.com/queues/jms.queue.bar/pull-consumers/acknowledged/333
+msg-acknowledge-next: http://example.com/queues/jms.queue.bar/pull-consumers/acknowledged/333/acknowledge-next-1
+
+ The
+ Location
+ header points to the JMS
+ consumer resource that was created on the server. It is good to
+ remember this URL, although, as you'll see later, it is
+ transmitted with each response just to remind you.
+
+
+
+
+ Creating an manually-acknowledged consumer for a topic is pretty
+ much the same. Here's an example of creating a durable
+ manually-acknowledged topic pull subscription.
+
+
+
+
+ Find the
+ pull-subscriptions
+ URL by doing
+ a HEAD or GET request to the base topic resource
+
+
+
+HEAD /topics/jms.topic.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/topics/jms.topic.foo/create
+msg-pull-subscriptions: http://example.com/topics/jms.topic.foo/pull-subscriptions
+msg-push-subscriptions: http://example.com/topics/jms.topic.foo/push-subscriptions
+
+
+
+ Next do a POST to the URL returned in the
+ msg-pull-subscriptions
+ header passing in a true
+ value for the durable
+ form parameter and a false
+ value to the autoAck
+ form parameter.
+
+
+
+POST /topics/jms.topic.foo/pull-subscriptions HTTP/1.1
+Host: example.com
+Content-Type: application/x-www-form-urlencoded
+
+durable=true&autoAck=false
+
+--- Response ---
+HTTP/1.1 201 Created
+Location: http://example.com/topics/jms.topic.foo/pull-subscriptions/acknowledged/222
+msg-acknowledge-next:
+http://example.com/topics/jms.topic.foo/pull-subscriptions/acknowledged/222/consume-next-1
+
+ The
+ Location header points to the JMS
+ subscription resource that was created on the server. It is good
+ to remember this URL, although, as you'll see later, it is
+ transmitted with each response just to remind you.
+
+
+
+
+
+
+ Consuming and Acknowledging a Message
+
+ After you have created a consumer resource, you are ready to
+ start pulling messages from the server. Notice that when you created
+ the consumer for either the queue or topic, the response contained a
+ msg-acknowledge-next response header. POST to the
+ URL contained within this header to consume the next message in the
+ queue or topic subscription. If there are no messages in the queue or
+ topic subscription, a 503 (Service Unavailable) HTTP code is returned.
+ A successful POST causes the server to extract a message from the
+ queue or topic subscription and return it to the consuming client. It
+ does not acknowledge the message though. The response will contain the
+ acknowledgement
+ header which you will use to
+ acknowledge the message.
+
+
+ Here's an example of pulling multiple messages from the consumer
+ resource.
+
+
+
+
+ Do a POST on the msg-acknowledge-next URL that was returned
+ with the consumer or subscription resource discussed
+ earlier.
+
+
+
+POST /queues/jms.queue.bar/pull-consumers/consume-next-1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+Content-Type: application/xml
+msg-acknowledgement:
+http://example.com/queues/jms.queue.bar/pull-consumers/333/acknowledgement/2
+msg-consumer: http://example.com/queues/jms.queue.bar/pull-consumers/333
+
+<order>...</order>
+
+ The POST returns the message consumed from the queue. It
+ also returns amsg-acknowledgement link. You
+ will use this new link to acknowledge the message. Notice also a
+ msg-consumer response header is returned. This
+ is a URL that points back to the consumer or subscription
+ resource. You will need that to clean up your connection after you
+ are finished using the queue or topic.
+
+
+
+
+ Acknowledge or unacknowledge the message by doing a POST to
+ the URL contained in the msg-acknowledgement
+ header. You must pass an acknowledge
+ form parameter set to true
+ or false depending on whether you want to
+ acknowledge or unacknowledge the message on the server.
+
+
+
+POST /queues/jms.queue.bar/pull-consumers/acknowledgement/2
+Host: example.com
+Content-Type: application/x-www-form-urlencoded
+
+acknowledge=true
+
+--- Response ---
+Http/1.1 200 Ok
+msg-acknowledge-next:
+http://example.com/queues/jms.queue.bar/pull-consumers/333/acknowledge-next-2
+
+ Whether you acknowledge or unacknowledge the message, the
+ response will contain a new msg-acknowledge-next header that you
+ must use to obtain the next message.
+
+
+
+
+
+
+ Recovering From Network Failures
+
+ If you experience a network failure and do not know if your post
+ to a
+ msg-acknowledge-next
+ or
+ msg-acknowledgement URL was successful or not, just
+ re-do your POST. A POST to one of these URLs is idempotent, meaning
+ that it will return the same result if you re-post. Behind the scenes,
+ the consumer resource keeps track of its current state. If the last
+ action was a call tomsg-acknowledge-next, it will
+ have the last message cached, so that if a re-post is done, it will
+ return the message again. Same goes with re-posting to
+ msg-acknowledgement. The server remembers its last
+ state and will return the same results. If you look at the URLs you'll
+ see that they contain information about the expected current state of
+ the server. This is how the server knows what the client is
+ expecting.
+
+
+
+
+ Recovering From Client or Server Crashes
+
+ If the server crashes and while you are doing a POST to the
+ msg-acknowledge-next URL, just re-post. Everything
+ should reconnect all right. On the other hand, if the server crashes
+ while you are doing a POST tomsg-acknowledgement,
+ the server will return a 412 (Preconditions Failed) response code.
+ This is telling you that the URL you are using is out of sync with the
+ server and the message you are acknowledging was probably re-enqueued.
+ The response will contain a new msg-acknowledge-next
+ header to invoke on.
+
+
+ As long as you have "bookmarked" the consumer resource URL
+ (returned from Location header on a create, or the
+ msg-consumer header), you can recover from client
+ crashes by doing a GET or HEAD request on the consumer resource to
+ obtain what state you are in. If the consumer resource is expecting
+ you to acknowledge a message, it will return a
+ msg-acknowledgement header in the response. If the
+ consumer resource is expecting you to pull for the next message, the
+ msg-acknowledge-next header will be in the
+ response. With manual acknowledgement you are pretty much guaranteed
+ to avoid skipped messages. For topic subscriptions that were created
+ with a name parameter, you do not have to "bookmark" the returned URL.
+ Instead, you can re-create the consumer resource with the same exact
+ name. The response will contain the same information as if you did a
+ GET or HEAD request on the consumer resource.
+
+
+
+
+
+ Blocking Pulls with Accept-Wait
+
+ Unless your queue or topic has a high rate of message flowing
+ though it, if you use the pull protocol, you're going to be receiving a
+ lot of 503 responses as you continuously pull the server for new
+ messages. To alleviate this problem, the HornetQ REST interface provides
+ the Accept-Wait header. This is a generic HTTP
+ request header that is a hint to the server for how long the client is
+ willing to wait for a response from the server. The value of this header
+ is the time in seconds the client is willing to block for. You would
+ send this request header with your pull requests. Here's an
+ example:
+
+
+
+POST /queues/jms.queue.bar/pull-consumers/consume-next-2
+Host: example.com
+Accept-Wait: 30
+
+--- Response ---
+HTTP/1.1 200 Ok
+Content-Type: application/xml
+msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-3
+
+<order>...</order>
+
+ In this example, we're posting to a msg-consume-next URL and
+ telling the server that we would be willing to block for 30
+ seconds.
+
+
+
+
+ Clean Up Your Consumers!
+
+ When the client is done with its consumer or topic subscription it
+ should do an HTTP DELETE call on the consumer URL passed back from the
+ Location header or the msg-consumer response header. The server will
+ time out a consumer with the value of
+ consumer-session-timeout-seconds configured from
+ REST configuration, so you
+ don't have to clean up if you don't want to, but if you are a good kid,
+ you will clean up your messes. A consumer timeout for durable
+ subscriptions will not delete the underlying durable JMS subscription
+ though, only the server-side consumer resource (and underlying JMS
+ session).
+
+
+
+
+
+
+ Pushing Messages
+
+ You can configure the HornetQ REST server to push messages to a
+ registered URL either remotely through the REST interface, or by creating
+ a pre-configured XML file for the HornetQ REST server to load at boot
+ time.
+
+
+
+ The Queue Push Subscription XML
+
+ Creating a push consumer for a queue first involves creating a
+ very simple XML document. This document tells the server if the push
+ subscription should survive server reboots (is it durable). It must
+ provide a URL to ship the forwarded message to. Finally, you have to
+ provide authentication information if the final endpoint requires
+ authentication. Here's a simple example:
+
+
+
+<push-registration>
+ <durable>false</durable>
+ <selector><![CDATA[
+ SomeAttribute > 1
+ ]]>
+ </selector>
+ <link rel="push" href="http://somewhere.com" type="application/json" method="PUT"/>
+ <maxRetries>5</maxRetries>
+ <retryWaitMillis>1000</retryWaitMillis>
+ <disableOnFailure>true</disableOnFailure>
+</push-registration>
+
+ The durable element specifies whether the
+ registration should be saved to disk so that if there is a server
+ restart, the push subscription will still work. This element is not
+ required. If left out it defaults tofalse. If
+ durable is set to true, an XML file for the push subscription will be
+ created within the directory specified by the
+ queue-push-store-dir config variable defined in
+ Chapter 2 (topic-push-store-dir for topics).
+
+
+ The selector element is optional and defines a
+ JMS message selector. You should enclose it within CDATA blocks as some
+ of the selector characters are illegal XML.
+
+
+ The maxRetries element specifies how many times
+ a the server will try to push a message to a URL if there is a
+ connection failure.
+
+
+ The retryWaitMillis element specifies how long
+ to wait before performing a retry.
+
+
+ The
+ disableOnFailure element, if set to true,
+ will disable the registration if all retries have failed. It will not
+ disable the connection on non-connection-failure issues (like a bad
+ request for instance). In these cases, the dead letter queue logic of
+ HornetQ will take over.
+
+
+ The link element specifies the basis of the
+ interaction. The href attribute contains the URL you
+ want to interact with. It is the only required attribute. The
+ type attribute specifies the content-type of what the
+ push URL is expecting. The method attribute defines
+ what HTTP method the server will use when it sends the message to the
+ server. If it is not provided it defaults to POST. The
+ rel attribute is very important and the value of it
+ triggers different behavior. Here's the values a rel attribute can
+ have:
+
+
+
+
+ destination. The href URL is assumed to be a queue or topic resource of
+ another HornetQ REST server. The push registration will initially
+ do a HEAD request to this URL to obtain a msg-create-with-id
+ header. It will use this header to push new messages to the
+ HornetQ REST endpoint reliably. Here's an example:
+
+
+
+<push-registration>
+ <link rel="destination" href="http://somewhere.com/queues/jms.queue.foo"/>
+</push-registration>
+
+
+ template. In this case, the server is expecting the link element's
+ href attribute to be a URL expression. The URL expression must
+ have one and only one URL parameter within it. The server will use
+ a unique value to create the endpoint URL. Here's an
+ example:
+
+
+
+<push-registration>
+ <link rel="template" href="http://somewhere.com/resources/{id}/messages" method="PUT"/>
+</push-registration>
+
+ In this example, the {id} sub-string is the one and only one
+ URL parameter.
+
+
+
+ user defined. If the rel attributes is not destination or template (or is
+ empty or missing), then the server will send an HTTP message to
+ the href URL using the HTTP method defined in the method
+ attribute. Here's an example:
+
+
+
+<push-registration>
+ <link href="http://somewhere.com" type="application/json" method="PUT"/>
+</push-registration>
+
+
+
+
+
+ The Topic Push Subscription XML
+
+ The push XML for a topic is the same except the root element is
+ push-topic-registration. (Also remember the selector
+ element is optional). The rest of the document is the same. Here's an
+ example of a template registration:
+
+
+
+<push-topic-registration>
+ <durable>true</durable>
+ <selector><![CDATA[
+ SomeAttribute > 1
+ ]]>
+ </selector>
+ <link rel="template" href="http://somewhere.com/resources/{id}/messages" method="POST"/>
+</push-topic registration>
+
+
+
+ Creating a Push Subscription at Runtime
+
+ Creating a push subscription at runtime involves getting the
+ factory resource URL from the msg-push-consumers header, if the
+ destination is a queue, or msg-push-subscriptions header, if the
+ destination is a topic. Here's an example of creating a push
+ registration for a queue:
+
+
+
+
+ First do a HEAD request to the queue resource:
+
+
+HEAD /queues/jms.queue.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/queues/jms.queue.bar/create
+msg-pull-consumers: http://example.com/queues/jms.queue.bar/pull-consumers
+msg-push-consumers: http://example.com/queues/jms.queue.bar/push-consumers
+
+
+
+ Next POST your subscription XML to the URL returned from
+ msg-push-consumers header
+
+
+
+POST /queues/jms.queue.bar/push-consumers
+Host: example.com
+Content-Type: application/xml
+
+<push-registration>
+ <link rel="destination" href="http://somewhere.com/queues/jms.queue.foo"/>
+</push-registration>
+
+--- Response ---
+HTTP/1.1 201 Created
+Location: http://example.com/queues/jms.queue.bar/push-consumers/1-333-1212
+
+ The Location header contains the URL for the created resource.
+ If you want to unregister this, then do a HTTP DELETE on this
+ URL.
+
+
+
+
+ Here's an example of creating a push registration for a
+ topic:
+
+
+
+
+ First do a HEAD request to the topic resource:
+
+
+HEAD /topics/jms.topic.bar HTTP/1.1
+Host: example.com
+
+--- Response ---
+HTTP/1.1 200 Ok
+msg-create: http://example.com/topics/jms.topic.bar/create
+msg-pull-subscriptions: http://example.com/topics/jms.topic.bar/pull-subscriptions
+msg-push-subscriptions: http://example.com/topics/jms.topic.bar/push-subscriptions
+
+
+
+ Next POST your subscription XML to the URL returned from
+ msg-push-subscriptions header
+
+
+
+POST /topics/jms.topic.bar/push-subscriptions
+Host: example.com
+Content-Type: application/xml
+
+<push-registration>
+ <link rel="template" href="http://somewhere.com/resources/{id}"/>
+</push-registration>
+
+--- Response ---
+HTTP/1.1 201 Created
+Location: http://example.com/topics/jms.topic.bar/push-subscriptions/1-333-1212
+
+ The Location header contains the URL for the created resource.
+ If you want to unregister this, then do a HTTP DELETE on this
+ URL.
+
+
+
+
+
+
+ Creating a Push Subscription by Hand
+
+ You can create a push XML file yourself if you do not want to go
+ through the REST interface to create a push subscription. There is some
+ additional information you need to provide though. First, in the root
+ element, you must define a unique id attribute. You must also define a
+ destination element to specify the queue you should register a consumer
+ with. For a topic, the destination element is the name of the
+ subscription that will be created. For a topic, you must also specify the
+ topic name within the topic element.
+
+
+ Here's an example of a hand-created queue registration. This file
+ must go in the directory specified by the queue-push-store-dir config
+ variable defined in Chapter 2:
+
+
+
+<push-registration id="111">
+ <destination>jms.queue.bar</destination>
+ <durable>true</durable>
+ <link rel="template" href="http://somewhere.com/resources/{id}/messages" method="PUT"/>
+</push-registration>
+
+ Here's an example of a hand-created topic registration. This file
+ must go in the directory specified by the topic-push-store-dir config
+ variable defined in Chapter 2:
+
+
+
+<push-topic-registration id="112">
+ <destination>my-subscription-1</destination
+ <durable>true</durable>
+ <link rel="template" href="http://somewhere.com/resources/{id}/messages" method="PUT"/>
+ <topic>jms.topic.foo</topic>
+</push-topic-registration>
+
+
+
+ Pushing to Authenticated Servers
+
+ Push subscriptions only support BASIC and DIGEST authentication
+ out of the box. Here is an example of adding BASIC
+ authentication:
+
+
+
+<push-topic-registration>
+ <durable>true</durable>
+ <link rel="template" href="http://somewhere.com/resources/{id}/messages" method="POST"/>
+ <authentication>
+ <basic-auth>
+ <username>guest</username>
+ <password>geheim</password>
+ </basic-auth>
+ </authentication>
+</push-topic registration>
+
+ For DIGEST, just replace basic-auth with digest-auth.
+
+ For other authentication mechanisms, you can register headers you
+ want transmitted with each request. Use the header element with the name
+ attribute representing the name of the header. Here's what custom
+ headers might look like:
+
+
+
+<push-topic-registration>
+ <durable>true</durable>
+ <link rel="template" href="http://somewhere.com/resources/{id}/messages" method="POST"/>
+ <header name="secret-header">jfdiwe3321</header>
+</push-topic registration>
+
+
+
+
+
+ Creating Destinations
+
+ You can create a durable queue or topic through the REST interface.
+ Currently you cannot create a temporary queue or topic. To create a queue
+ you do a POST to the relative URL /queues with an XML representation of
+ the queue. The XML syntax is the same queue syntax that you would specify
+ in hornetq-jms.xml if you were creating a queue there. For example:
+
+
+
+POST /queues
+Host: example.com
+Content-Type: application/hornetq.jms.queue+xml
+
+<queue name="testQueue">
+ <durable>true</durable>
+</queue>
+
+--- Response ---
+HTTP/1.1 201 Created
+Location: http://example.com/queues/jms.queue.testQueue
+
+ Notice that the Content-Type is application/hornetq.jms.queue+xml.
+
+ Here's what creating a topic would look like:
+
+
+POST /topics
+Host: example.com
+Content-Type: application/hornetq.jms.topic+xml
+
+<topic name="testTopic">
+</topic>
+
+--- Response ---
+HTTP/1.1 201 Created
+Location: http://example.com/topics/jms.topic.testTopic
+
+
+
+
+ Securing the HornetQ REST Interface
+
+
+ Within JBoss Application server
+
+ Securing the HornetQ REST interface is very simple with the JBoss
+ Application Server. You turn on authentication for all URLs within your
+ WAR's web.xml, and let the user Principal to propagate to HornetQ. This
+ only works if you are using the JBossSecurityManager with HornetQ. See
+ the HornetQ documentation for more details.
+
+
+
+
+ Security in other environments
+
+ To secure the HornetQ REST interface in other environments you
+ must role your own security by specifying security constraints with your
+ web.xml for every path of every queue and topic you have deployed. Here
+ is a list of URI patterns:
+
+
+
+
+
+
+ /queues
+
+ secure the POST operation to secure queue creation
+
+
+
+ /queues/{queue-name}
+
+ secure the GET HEAD operation to getting information about the queue.
+
+
+
+ /queues/{queue-name}/create/*
+
+ secure this URL pattern for producing messages.
+
+
+
+ /queues/{queue-name}/pull-consumers/*
+
+ secure this URL pattern for pulling messages.
+
+
+
+ /queues/{queue-name}/push-consumers/*
+
+ secure this URL pattern for pushing messages.
+
+
+
+ /topics
+
+ secure the POST operation to secure topic creation
+
+
+
+ /topics/{topic-name}
+
+ secure the GET HEAD operation to getting information about the topic.
+
+
+
+ /topics/{topic-name}/create/*
+
+ secure this URL pattern for producing messages.
+
+
+
+ /topics/{topic-name}/pull-subscriptions/*
+
+ secure this URL pattern for pulling messages.
+
+
+
+ /topics/{topic-name}/push-subscriptions/*
+
+ secure this URL pattern for pushing messages.
+
+
+
+
+
+
+
+
+
+ Mixing JMS and REST
+
+ The HornetQ REST interface supports mixing JMS and REST producers
+ and consumers. You can send an ObjectMessage through a JMS Producer, and
+ have a REST client consume it. You can have a REST client POST a message
+ to a topic and have a JMS Consumer receive it. Some simple transformations
+ are supported if you have the correct RESTEasy providers installed.
+
+
+
+ JMS Producers - REST Consumers
+
+ If you have a JMS producer, the HornetQ REST interface only
+ supports ObjectMessage type. If the JMS producer is aware that there may
+ be REST consumers, it should set a JMS property to specify what
+ Content-Type the Java object should be translated into by REST clients.
+ The HornetQ REST server will use RESTEasy content handlers
+ (MessageBodyReader/Writers) to transform the Java object to the type
+ desired. Here's an example of a JMS producer setting the content type of
+ the message.
+
+
+
+ObjectMessage message = session.createObjectMessage();
+message.setStringProperty(org.hornetq.rest.HttpHeaderProperty.CONTENT_TYPE, "application/xml");
+
+ If the JMS producer does not set the content-type, then this
+ information must be obtained from the REST consumer. If it is a pull
+ consumer, then the REST client should send an Accept header with the
+ desired media types it wants to convert the Java object into. If the
+ REST client is a push registration, then the type attribute of the link
+ element of the push registration should be set to the desired
+ type.
+
+
+
+
+ REST Producers - JMS Consumers
+
+ If you have a REST client producing messages and a JMS consumer,
+ HornetQ REST has a simple helper class for you to transform the HTTP
+ body to a Java object. Here's some example code:
+
+
+
+public void onMessage(Message message)
+{
+ MyType obj = org.hornetq.rest.Jms.getEntity(message, MyType.class);
+}
+
+ The way the getEntity() method works is that if
+ the message is an ObjectMessage, it will try to extract the desired type
+ from it like any other JMS message. If a REST producer sent the message,
+ then the method uses RESTEasy to convert the HTTP body to the Java
+ object you want. See the Javadoc of this class for more helper
+ methods.
+
+
+
+
diff --git a/docs/user-manual/en/scheduled-messages.xml b/docs/user-manual/en/scheduled-messages.xml
new file mode 100644
index 0000000000..509904e9e4
--- /dev/null
+++ b/docs/user-manual/en/scheduled-messages.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Scheduled Messages
+ Scheduled messages differ from normal messages in that they won't be delivered until a
+ specified time in the future, at the earliest.
+ To do this, a special property is set on the message before sending it.
+
+ Scheduled Delivery Property
+ The property name used to identify a scheduled message is "_HQ_SCHED_DELIVERY" (or the constant Message.HDR_SCHEDULED_DELIVERY_TIME).
+ The specified value must be a positive long corresponding to the time the
+ message must be delivered (in milliseconds). An example of sending a scheduled message
+ using the JMS API is as follows.
+
+TextMessage message = session.createTextMessage("This is a scheduled message message which will be delivered in 5 sec.");
+message.setLongProperty("_HQ_SCHED_DELIVERY", System.currentTimeMillis() + 5000);
+producer.send(message);
+
+...
+
+// message will not be received immediately but 5 seconds later
+TextMessage messageReceived = (TextMessage) consumer.receive();
+ Scheduled messages can also be sent using the core API, by setting the same property on
+ the core message before sending.
+
+
+ Example
+ See for an example which shows how
+ scheduled messages can be used with JMS.
+
+
diff --git a/docs/user-manual/en/security.xml b/docs/user-manual/en/security.xml
new file mode 100644
index 0000000000..91a832e9f0
--- /dev/null
+++ b/docs/user-manual/en/security.xml
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Security
+ This chapter describes how security works with HornetQ and how you can configure it. To
+ disable security completely simply set the security-enabled property to
+ false in the hornetq-configuration.xml file.
+ For performance reasons security is cached and invalidated every so long. To change this
+ period set the property security-invalidation-interval, which is in
+ milliseconds. The default is 10000 ms.
+
+ Role based security for addresses
+ HornetQ contains a flexible role-based security model for applying security to queues,
+ based on their addresses.
+ As explained in , HornetQ core consists mainly of sets of
+ queues bound to addresses. A message is sent to an address and the server looks up the
+ set of queues that are bound to that address, the server then routes the message to
+ those set of queues.
+ HornetQ allows sets of permissions to be defined against the queues based on their
+ address. An exact match on the address can be used or a wildcard match can be used using
+ the wildcard characters '#' and '*'.
+ Seven different permissions can be given to the set of queues which match the address.
+ Those permissions are:
+
+
+ createDurableQueue. This permission allows the user to
+ create a durable queue under matching addresses.
+
+
+ deleteDurableQueue. This permission allows the user to
+ delete a durable queue under matching addresses.
+
+
+ createNonDurableQueue. This permission allows the user to create
+ a non-durable queue under matching addresses.
+
+
+ deleteNonDurableQueue. This permission allows the user to delete
+ a non-durable queue under matching addresses.
+
+
+ send. This permission allows the user to send a message to
+ matching addresses.
+
+
+ consume. This permission allows the user to consume a
+ message from a queue bound to matching addresses.
+
+
+ manage. This permission allows the user to invoke
+ management operations by sending management messages to the management
+ address.
+
+
+ For each permission, a list of roles who are granted that permission is specified. If
+ the user has any of those roles, he/she will be granted that permission for that set of
+ addresses.
+ Let's take a simple example, here's a security block from hornetq-configuration.xml or hornetq-queues.xml
+ file:
+
+<security-setting match="globalqueues.europe.#">
+ <permission type="createDurableQueue" roles="admin"/>
+ <permission type="deleteDurableQueue" roles="admin"/>
+ <permission type="createNonDurableQueue" roles="admin, guest, europe-users"/>
+ <permission type="deleteNonDurableQueue" roles="admin, guest, europe-users"/>
+ <permission type="send" roles="admin, europe-users"/>
+ <permission type="consume" roles="admin, europe-users"/>
+</security-setting>
+ The '#' character signifies "any sequence of words". Words are
+ delimited by the '.' character. For a full description of the
+ wildcard syntax please see . The above security block
+ applies to any address that starts with the string "globalqueues.europe.":
+ Only users who have the admin role can create or delete durable
+ queues bound to an address that starts with the string "globalqueues.europe."
+ Any users with the roles admin, guest, or
+ europe-users can create or delete temporary queues bound to an
+ address that starts with the string "globalqueues.europe."
+ Any users with the roles admin or europe-users
+ can send messages to these addresses or consume messages from queues bound to an address
+ that starts with the string "globalqueues.europe."
+ The mapping between a user and what roles they have is handled by the security
+ manager. HornetQ ships with a user manager that reads user credentials from a file on
+ disk, and can also plug into JAAS or JBoss Application Server security.
+ For more information on configuring the security manager, please see .
+ There can be zero or more security-setting elements in each xml
+ file. Where more than one match applies to a set of addresses the more
+ specific match takes precedence.
+ Let's look at an example of that, here's another security-setting
+ block:
+
+<security-setting match="globalqueues.europe.orders.#">
+ <permission type="send" roles="europe-users"/>
+ <permission type="consume" roles="europe-users"/>
+</security-setting>
+ In this security-setting block the match
+ 'globalqueues.europe.orders.#' is more specific than the previous match
+ 'globalqueues.europe.#'. So any addresses which match 'globalqueues.europe.orders.#'
+ will take their security settings only from the latter
+ security-setting block.
+ Note that settings are not inherited from the former block. All the settings will be
+ taken from the more specific matching block, so for the address
+ 'globalqueues.europe.orders.plastics' the only permissions that exist are send and consume for the role europe-users. The
+ permissions createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue are not inherited from the other security-setting
+ block.
+ By not inheriting permissions, it allows you to effectively deny permissions in more
+ specific security-setting blocks by simply not specifying them. Otherwise it would not
+ be possible to deny permissions in sub-groups of addresses.
+
+
+ Secure Sockets Layer (SSL) Transport
+ When messaging clients are connected to servers, or servers are connected to other
+ servers (e.g. via bridges) over an untrusted network then HornetQ allows that traffic to
+ be encrypted using the Secure Sockets Layer (SSL) transport.
+ For more information on configuring the SSL transport, please see .
+
+
+ Basic user credentials
+ HornetQ ships with a security manager implementation that reads user credentials, i.e.
+ user names, passwords and role information from an xml file on the classpath called
+ hornetq-users.xml. This is the default security manager.
+ If you wish to use this security manager, then users, passwords and roles can easily
+ be added into this file.
+ Let's take a look at an example file:
+
+<configuration xmlns="urn:hornetq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:hornetq ../schemas/hornetq-users.xsd ">
+
+ <defaultuser name="guest" password="guest">
+ <role name="guest"/>
+ </defaultuser>
+
+ <user name="tim" password="marmite">
+ <role name="admin"/>
+ </user>
+
+ <user name="andy" password="doner_kebab">
+ <role name="admin"/>
+ <role name="guest"/>
+ </user>
+
+ <user name="jeff" password="camembert">
+ <role name="europe-users"/>
+ <role name="guest"/>
+ </user>
+
+</configuration>
+ The first thing to note is the element defaultuser. This defines
+ what user will be assumed when the client does not specify a username/password when
+ creating a session. In this case they will be the user guest and have
+ the role also called guest. Multiple roles can be specified for a
+ default user.
+ We then have three more users, the user tim has the role admin. The user andy has the roles admin and guest, and the user jeff
+ has the roles europe-users and guest.
+
+
+ Changing the security manager
+ If you do not want to use the default security manager then you can specify a
+ different one by editing the file hornetq-beans.xml (or hornetq-jboss-beans.xml if you're running JBoss Application Server) and
+ changing the class for the HornetQSecurityManager bean.
+ Let's take a look at a snippet from the default beans file:
+
+<bean name="HornetQSecurityManager" class="org.hornetq.spi.core.security.HornetQSecurityManagerImpl">
+ <start ignored="true"/>
+ <stop ignored="true"/>
+</bean>
+ The class org.hornetq.spi.core.security.HornetQSecurityManagerImpl
+ is the default security manager that is used by the standalone server.
+ HornetQ ships with two other security manager implementations you can use
+ off-the-shelf; one a JAAS security manager and another for integrating with JBoss
+ Application Sever security, alternatively you could write your own implementation by
+ implementing the org.hornetq.spi.core.security.HornetQSecurityManager
+ interface, and specifying the classname of your implementation in the file hornetq-beans.xml (or hornetq-jboss-beans.xml if
+ you're running JBoss Application Server).
+ These two implementations are discussed in the next two sections.
+
+
+ JAAS Security Manager
+ JAAS stands for 'Java Authentication and Authorization Service' and is a standard part
+ of the Java platform. It provides a common API for security authentication and
+ authorization, allowing you to plugin your pre-built implementations.
+ To configure the JAAS security manager to work with your pre-built JAAS infrastructure
+ you need to specify the security manager as a JAASSecurityManager in
+ the beans file. Here's an example:
+
+<bean name="HornetQSecurityManager" class="org.hornetq.integration.jboss.security.JAASSecurityManager">
+ <start ignored="true"/>
+ <stop ignored="true"/>
+
+ <property name="ConfigurationName">org.hornetq.jms.example.ExampleLoginModule</property>
+ <property name="Configuration">
+ <inject bean="ExampleConfiguration"/>
+ </property>
+ <property name="CallbackHandler">
+ <inject bean="ExampleCallbackHandler"/>
+ </property>
+</bean>
+ Note that you need to feed the JAAS security manager with three properties:
+
+
+ ConfigurationName: the name of the LoginModule
+ implementation that JAAS must use
+
+
+ Configuration: the Configuration implementation used by
+ JAAS
+
+
+ CallbackHandler: the CallbackHandler implementation to use
+ if user interaction are required
+
+
+
+ Example
+ See for an example which shows how HornetQ can be
+ configured to use JAAS.
+
+
+
+ JBoss AS Security Manager
+ The JBoss AS security manager is used when running HornetQ inside the JBoss
+ Application server. This allows tight integration with the JBoss Application Server's
+ security model.
+ The class name of this security manager is org.hornetq.integration.jboss.security.JBossASSecurityManager
+ Take a look at one of the default hornetq-jboss-beans.xml files for
+ JBoss Application Server that are bundled in the distribution for an example of how this
+ is configured.
+
+ Configuring Client Login
+ JBoss can be configured to allow client login, basically this is when a JEE component such as a Servlet
+ or EJB sets security credentials on the current security context and these are used throughout the call.
+ If you would like these credentials to be used by HornetQ when sending or consuming messages then
+ set allowClientLogin to true. This will bypass HornetQ authentication and propagate the
+ provided Security Context. If you would like HornetQ to authenticate using the propagated security then set the
+ authoriseOnClientLogin to true also.
+ There is more info on using the JBoss client login module here
+ If messages are sent non blocking then there is a chance that these could arrive on the server after
+ the calling thread has completed meaning that the security context has been cleared. If this is the case then messages
+ will need to be sent blocking
+
+
+ Changing the Security Domain
+ The name of the security domain used by the JBoss AS security manager defaults to java:/jaas/hornetq
+ . This can be changed by specifying securityDomainName (e.g. java:/jaas/myDomain).
+
+
+
+
+ Changing the username/password for clustering
+ In order for cluster connections to work correctly, each node in the cluster must make
+ connections to the other nodes. The username/password they use for this should always be
+ changed from the installation default to prevent a security risk.
+ Please see for instructions on how to do this.
+
+
diff --git a/docs/user-manual/en/send-guarantees.xml b/docs/user-manual/en/send-guarantees.xml
new file mode 100644
index 0000000000..40a0bc5430
--- /dev/null
+++ b/docs/user-manual/en/send-guarantees.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Guarantees of sends and commits
+
+ Guarantees of Transaction Completion
+ When committing or rolling back a transaction with HornetQ, the request to commit or
+ rollback is sent to the server, and the call will block on the client side until a
+ response has been received from the server that the commit or rollback was
+ executed.
+ When the commit or rollback is received on the server, it will be committed to the
+ journal, and depending on the value of the parameter journal-sync-transactional the server will ensure that the commit or
+ rollback is durably persisted to storage before sending the response back to the client.
+ If this parameter has the value false then commit or rollback may not
+ actually get persisted to storage until some time after the response has been sent to
+ the client. In event of server failure this may mean the commit or rollback never gets
+ persisted to storage. The default value of this parameter is true so
+ the client can be sure all transaction commits or rollbacks have been persisted to
+ storage by the time the call to commit or rollback returns.
+ Setting this parameter to false can improve performance at the
+ expense of some loss of transaction durability.
+ This parameter is set in hornetq-configuration.xml
+
+
+ Guarantees of Non Transactional Message Sends
+ If you are sending messages to a server using a non transacted session, HornetQ can be
+ configured to block the call to send until the message has definitely reached the
+ server, and a response has been sent back to the client. This can be configured
+ individually for durable and non-durable messages, and is determined by the
+ following two parameters:
+
+
+ BlockOnDurableSend. If this is set to true then all calls to send for durable messages on non
+ transacted sessions will block until the message has reached the server, and a
+ response has been sent back. The default value is true.
+
+
+
+ BlockOnNonDurableSend. If this is set to true then all calls to send for non-durable messages on non
+ transacted sessions will block until the message has reached the server, and a
+ response has been sent back. The default value is false.
+
+
+ Setting block on sends to true can reduce performance since each
+ send requires a network round trip before the next send can be performed. This means the
+ performance of sending messages will be limited by the network round trip time (RTT) of
+ your network, rather than the bandwidth of your network. For better performance we
+ recommend either batching many messages sends together in a transaction since with a
+ transactional session, only the commit / rollback blocks not every send, or, using
+ HornetQ's advanced asynchronous send acknowledgements feature
+ described in .
+ If you are using JMS and you're using the JMS service on the server to load your JMS
+ connection factory instances into JNDI then these parameters can be configured in
+ hornetq-jms.xml using the elements block-on-durable-send and block-on-non-durable-send. If you're using JMS but not using JNDI then
+ you can set these values directly on the HornetQConnectionFactory
+ instance using the appropriate setter methods.
+ If you're using core you can set these values directly on the ClientSessionFactory instance using the appropriate setter
+ methods.
+ When the server receives a message sent from a non transactional session, and that
+ message is durable and the message is routed to at least one durable queue, then the
+ server will persist the message in permanent storage. If the journal parameter journal-sync-non-transactional is set to true the
+ server will not send a response back to the client until the message has been persisted
+ and the server has a guarantee that the data has been persisted to disk. The default
+ value for this parameter is true.
+
+
+ Guarantees of Non Transactional Acknowledgements
+ If you are acknowledging the delivery of a message at the client side using a non
+ transacted session, HornetQ can be configured to block the call to acknowledge until the
+ acknowledge has definitely reached the server, and a response has been sent back to the
+ client. This is configured with the parameter BlockOnAcknowledge. If
+ this is set to true then all calls to acknowledge on non transacted
+ sessions will block until the acknowledge has reached the server, and a response has
+ been sent back. You might want to set this to true if you want to
+ implement a strict at most once delivery policy. The default value
+ is false
+
+
+ Asynchronous Send Acknowledgements
+ If you are using a non transacted session but want a guarantee that every message sent
+ to the server has reached it, then, as discussed in , you can configure HornetQ to block the call to
+ send until the server has received the message, persisted it and sent back a response.
+ This works well but has a severe performance penalty - each call to send needs to block
+ for at least the time of a network round trip (RTT) - the performance of sending is thus
+ limited by the latency of the network, not limited by the network
+ bandwidth.
+ Let's do a little bit of maths to see how severe that is. We'll consider a standard
+ 1Gib ethernet network with a network round trip between the server and the client of
+ 0.25 ms.
+ With a RTT of 0.25 ms, the client can send at most 1000/ 0.25 =
+ 4000 messages per second if it blocks on each message send.
+ If each message is < 1500 bytes and a standard 1500 bytes MTU size is used on the
+ network, then a 1GiB network has a theoretical upper limit of (1024
+ * 1024 * 1024 / 8) / 1500 = 89478 messages per second if messages are sent without
+ blocking! These figures aren't an exact science but you can clearly see that being
+ limited by network RTT can have serious effect on performance.
+ To remedy this, HornetQ provides an advanced new feature called asynchronous
+ send acknowledgements. With this feature, HornetQ can be configured to
+ send messages without blocking in one direction and asynchronously getting
+ acknowledgement from the server that the messages were received in a separate stream. By
+ de-coupling the send from the acknowledgement of the send, the system is not limited by
+ the network RTT, but is limited by the network bandwidth. Consequently better throughput
+ can be achieved than is possible using a blocking approach, while at the same time
+ having absolute guarantees that messages have successfully reached the server.
+ The window size for send acknowledgements is determined by the confirmation-window-size parameter on
+ the connection factory or client session factory. Please see for more info on this.
+
+ Asynchronous Send Acknowledgements
+ To use the feature using the core API, you implement the interface org.hornetq.api.core.client.SendAcknowledgementHandler and set a handler
+ instance on your ClientSession.
+ Then, you just send messages as normal using your ClientSession, and as messages reach the server, the server will send
+ back an acknowledgement of the send asynchronously, and some time later you are
+ informed at the client side by HornetQ calling your handler's sendAcknowledged(ClientMessage message) method, passing in a
+ reference to the message that was sent.
+ To enable asynchronous send acknowledgements you must make sure confirmation-window-size is set to a positive integer value, e.g. 10MiB
+ Please see for a full
+ working example.
+
+
+
diff --git a/docs/user-manual/en/spring-integration.xml b/docs/user-manual/en/spring-integration.xml
new file mode 100644
index 0000000000..730fa02597
--- /dev/null
+++ b/docs/user-manual/en/spring-integration.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Spring Integration
+
+ HornetQ provides a simple bootstrap class,
+ org.hornetq.integration.spring.SpringJmsBootstrap, for
+ integration with Spring. To use it, you configure HornetQ as you always
+ would, through its various configuration files like
+ hornetq-configuration.xml,
+ hornetq-jms.xml, and
+ hornetq-users.xml. The Spring helper class starts the
+ HornetQ server and adds any factories or destinations configured within
+ hornetq-jms.xml directly into the namespace of the Spring
+ context. Let's take this hornetq-jms.xml file for
+ instance:
+
+<configuration xmlns="urn:hornetq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd">
+ <!--the connection factory used by the example-->
+ <connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="in-vm"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ </connection-factory>
+
+ <!--the queue used by the example-->
+ <queue name="exampleQueue">
+ <entry name="/queue/exampleQueue"/>
+ </queue>
+</configuration>
+ Here we've specified a
+ javax.jms.ConnectionFactory we want bound to a
+ ConnectionFactory entry as well as a queue destination
+ bound to a /queue/exampleQueue entry. Using the
+ SpringJmsBootStrap bean will automatically populate the
+ Spring context with references to those beans so that you can use them.
+ Below is an example Spring JMS bean file taking advantage of this
+ feature:
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
+
+ <bean id="EmbeddedJms" class="org.hornetq.integration.spring.SpringJmsBootstrap" init-method="start"/>
+
+ <bean id="listener" class="org.hornetq.tests.integration.spring.ExampleListener"/>
+
+ <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
+ <property name="connectionFactory" ref="ConnectionFactory"/>
+ <property name="destination" ref="/queue/exampleQueue"/>
+ <property name="messageListener" ref="listener"/>
+ </bean>
+</beans>
+ As you can see, the
+ listenerContainer bean references the components defined
+ in the hornetq-jms.xml file. The
+ SpringJmsBootstrap class extends the EmbeddedJMS class
+ talked about in and the same defaults and
+ configuration options apply. Also notice that an
+ init-method must be declared with a start value so that
+ the bean's lifecycle is executed. See the javadocs for more details on other
+ properties of the bean class.
+
diff --git a/docs/user-manual/en/thread-pooling.xml b/docs/user-manual/en/thread-pooling.xml
new file mode 100644
index 0000000000..e78b1b01fe
--- /dev/null
+++ b/docs/user-manual/en/thread-pooling.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Thread management
+ This chapter describes how HornetQ uses and pools threads and how you can manage
+ them.
+ First we'll discuss how threads are managed and used on the server side, then we'll look
+ at the client side.
+
+ Server-Side Thread Management
+ Each HornetQ Server maintains a single thread pool for general use, and a scheduled
+ thread pool for scheduled use. A Java scheduled thread pool cannot be configured to use
+ a standard thread pool, otherwise we could use a single thread pool for both scheduled
+ and non scheduled activity.
+ A separate thread pool is also used to service connections. HornetQ can use "old"
+ (blocking) IO or "new" (non-blocking) IO also called NIO. Both of these options use
+ a separate thread pool, but each of them behaves uniquely.
+ Since old IO requires a thread per connection its thread pool is unbounded. The thread
+ pool is created via
+ java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory). As the
+ JavaDoc for this method states:
+ Creates a thread pool that creates new threads as needed, but will reuse previously
+ constructed threads when they are available, and uses the provided ThreadFactory to create
+ new threads when needed.
+ Threads from this pool which are idle for more than 60 seconds will time out and be
+ removed. If old IO connections were serviced from the standard pool the pool would
+ easily get exhausted if too many connections were made, resulting in the server "hanging"
+ since it has no remaining threads to do anything else. However, even an unbounded thread
+ pool can run into trouble if it becomes too large. If you require the server to handle
+ many concurrent connections you should use NIO, not old IO.
+ When using new IO (NIO), HornetQ will, by default, cap its thread pool at three times
+ the number of cores (or hyper-threads) as reported by
+ Runtime.getRuntime().availableProcessors() for processing incoming packets.
+ To override this value, you can set the number of threads by specifying the parameter
+ nio-remoting-threads in the transport configuration. See the
+ for more information on this.
+ There are also a small number of other places where threads are used directly, we'll
+ discuss each in turn.
+
+ Server Scheduled Thread Pool
+ The server scheduled thread pool is used for most activities on the server side
+ that require running periodically or with delays. It maps internally to a java.util.concurrent.ScheduledThreadPoolExecutor instance.
+ The maximum number of thread used by this pool is configure in hornetq-configuration.xml with the scheduled-thread-pool-max-size parameter. The default value is
+ 5 threads. A small number of threads is usually sufficient
+ for this pool.
+
+
+ General Purpose Server Thread Pool
+ This general purpose thread pool is used for most asynchronous actions on the
+ server side. It maps internally to a java.util.concurrent.ThreadPoolExecutor instance.
+ The maximum number of thread used by this pool is configure in hornetq-configuration.xml with the thread-pool-max-size parameter.
+ If a value of -1 is used this signifies that the thread pool
+ has no upper bound and new threads will be created on demand if there are not enough
+ threads available to satisfy a request. If activity later subsides then threads are
+ timed-out and closed.
+ If a value of n where nis a positive integer
+ greater than zero is used this signifies that the thread pool is bounded. If more
+ requests come in and there are no free threads in the pool and the pool is full then
+ requests will block until a thread becomes available. It is recommended that a
+ bounded thread pool is used with caution since it can lead to dead-lock situations
+ if the upper bound is chosen to be too low.
+ The default value for thread-pool-max-size is 30.
+ See the J2SE javadoc for more information on unbounded (cached), and bounded
+ (fixed) thread pools.
+
+
+ Expiry Reaper Thread
+ A single thread is also used on the server side to scan for expired messages in
+ queues. We cannot use either of the thread pools for this since this thread needs to
+ run at its own configurable priority.
+ For more information on configuring the reaper, please see .
+
+
+ Asynchronous IO
+ Asynchronous IO has a thread pool for receiving and dispatching events out of the
+ native layer. You will find it on a thread dump with the prefix
+ HornetQ-AIO-poller-pool. HornetQ uses one thread per opened file on the journal
+ (there is usually one).
+ There is also a single thread used to invoke writes on libaio. We do that to avoid
+ context switching on libaio that would cause performance issues. You will find this
+ thread on a thread dump with the prefix HornetQ-AIO-writer-pool.
+
+
+
+ Client-Side Thread Management
+ On the client side, HornetQ maintains a single static scheduled thread pool and a
+ single static general thread pool for use by all clients using the same classloader in
+ that JVM instance.
+ The static scheduled thread pool has a maximum size of 5 threads,
+ and the general purpose thread pool has an unbounded maximum size.
+ If required HornetQ can also be configured so that each ClientSessionFactory instance does not use these static pools but instead
+ maintains its own scheduled and general purpose pool. Any sessions created from that
+ ClientSessionFactory will use those pools instead.
+ To configure a ClientSessionFactory instance to use its own pools,
+ simply use the appropriate setter methods immediately after creation, for
+ example:
+
+ServerLocator locator = HornetQClient.createServerLocatorWithoutHA(...)
+ClientSessionFactory myFactory = locator.createClientSessionFactory();
+myFactory.setUseGlobalPools(false);
+myFactory.setScheduledThreadPoolMaxSize(10);
+myFactory.setThreadPoolMaxSize(-1);
+ If you're using the JMS API, you can set the same parameters on the
+ ClientSessionFactory and use it to create the ConnectionFactory
+ instance, for example:
+
+ConnectionFactory myConnectionFactory = HornetQJMSClient.createConnectionFactory(myFactory);
+ If you're using JNDI to instantiate HornetQConnectionFactory
+ instances, you can also set these parameters in the hornetq-jms.xml
+ file where you describe your connection factory, for example:
+
+<connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ <entry name="XAConnectionFactory"/>
+ </entries>
+ <use-global-pools>false</use-global-pools>
+ <scheduled-thread-pool-max-size>10</scheduled-thread-pool-max-size>
+ <thread-pool-max-size>-1</thread-pool-max-size>
+</connection-factory>
+
+
diff --git a/docs/user-manual/en/tools.xml b/docs/user-manual/en/tools.xml
new file mode 100644
index 0000000000..12bf70e5ce
--- /dev/null
+++ b/docs/user-manual/en/tools.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %BOOK_ENTITIES;
+ ]>
+
+ Tools
+
+ HornetQ ships with several helpful command line tools. All tools are available from the hornetq-tools-<version>-jar-with-dependencies.jar.
+ As the name suggests, this Java archive contains HornetQ along with all of its dependencies. This is done to
+ simplify the execution of the tools by eliminating the need so specify a classpath. These tools are:
+
+
+ print-data. Used for low-level inspection of the bindings and message journals. It
+ takes two parameters - bindings-directory and journal-directory. These
+ are the paths to the directories where the bindings and message journals are stored, respectively. For
+ example:
+
+ java -jar hornetq-tools-<version>-jar-with-dependencies.jar print-data /home/user/hornetq/data/bindings /home/user/hornetq/data/journal
+
+
+ print-pages. Used for low-level inspection of paged message data. It takes two
+ parameters - paging-directory and journal-directory. These are the
+ paths to the directories where paged messages and the message journals are stored, respectively. For
+ example:
+
+ java -jar hornetq-tools-<version>-jar-with-dependencies.jar print-pages /home/user/hornetq/data/paging-directory /home/user/hornetq/data/journal
+
+
+ export. Used for exporting all binding and message data (including paged and large
+ messages) as well as JMS destinations and connection factories (including JNDI bindings). The export is
+ structured as XML. This data can then be imported to another server even if the server is a different
+ version than the original. It takes 4 parameters:
+
+
+
+ bindings-directory - the path to the bindings directory.
+
+
+ journal-directory - the path to the journal directory.
+
+
+ paging-directory - the path to the paging directory.
+
+
+ large-messages-directory - the path to the large-messages directory.
+
+
+ Here's an example:
+ java -jar hornetq-tools-<version>-jar-with-dependencies.jar export /home/user/hornetq/data/bindings-directory /home/user/hornetq/data/journal-directory /home/user/hornetq/data/paging-directory /home/user/hornetq/data/large-messages
+ This tool will export directly to standard out so if the data needs to be stored in a file please
+ redirect as appropriate for the operation system in use. Also, please note that the export
+ tool is single threaded so depending on the size of the journal it could take awhile to complete.
+
+
+
+ import. Used for importing data from an XML document generated by the
+ export tool. The import tool reads the XML document and connects
+ to a HornetQ server via Netty to import all the data. It takes 5 parameters:
+
+
+
+ input-file - the path to the XML file generated by the export
+ tool.
+
+
+
+ host - the IP address or hostname of the server where the data should be
+ imported.
+
+
+
+ port - the port where HornetQ is listening.
+
+
+ transactional - a boolean flag to indicate whether or not to
+ send all the message data in a single transaction. Valid values are true
+ or false.
+
+
+
+ application-server-compatibility - a boolean flag to indicate
+ whether or not JNDI bindings need special treatment to account for the way JBoss AS7, Wildfly, and
+ JBoss EAP 6 handle JNDI for remote clients. Each of these application servers require a special JNDI
+ binding to allow access from remote clients. If this is true then every JNDI
+ binding in the XML will be duplicated in the "java:jboss/exported/" namespace thus allowing both local
+ and remote clients to use the same name when accessing resources via JNDI. Valid values are
+ true or false.
+
+
+
+ Here's an example:
+ java -jar hornetq-tools-<version>-jar-with-dependencies.jar import /home/user/exportData.xml 127.0.0.1 5445 false false
+ Like the export tool the import tool is single threaded so
+ depending on the size of the XML file it may take awhile for the process to complete.
+
+
+
+
diff --git a/docs/user-manual/en/transaction-config.xml b/docs/user-manual/en/transaction-config.xml
new file mode 100644
index 0000000000..4f0905e3a8
--- /dev/null
+++ b/docs/user-manual/en/transaction-config.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Resource Manager Configuration
+ HornetQ has its own Resource Manager for handling the lifespan of JTA transactions. When a
+ transaction is started the resource manager is notified and keeps a record of the
+ transaction and its current state. It is possible in some cases for a transaction to be
+ started but then forgotten about. Maybe the client died and never came back. If this happens
+ then the transaction will just sit there indefinitely.
+ To cope with this HornetQ can, if configured, scan for old transactions and rollback any
+ it finds. The default for this is 3000000 milliseconds (5 minutes), i.e. any transactions older
+ than 5 minutes are removed. This timeout can be changed by editing the transaction-timeout property in hornetq-configuration.xml (value must be in milliseconds).
+ The property transaction-timeout-scan-period configures how often, in
+ milliseconds, to scan for old transactions.
+ Please note that HornetQ will not unilaterally rollback any XA transactions in a prepared state - this must be heuristically rolled
+ back via the management API if you are sure they will never be resolved by the transaction manager.
+
diff --git a/docs/user-manual/en/undelivered-messages.xml b/docs/user-manual/en/undelivered-messages.xml
new file mode 100644
index 0000000000..ec76c5d30f
--- /dev/null
+++ b/docs/user-manual/en/undelivered-messages.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Message Redelivery and Undelivered Messages
+ Messages can be delivered unsuccessfully (e.g. if the transacted session used to consume
+ them is rolled back). Such a message goes back to its queue ready to be redelivered. However,
+ this means it is possible for a message to be delivered again and again without any success
+ and remain in the queue, clogging the system.
+ There are 2 ways to deal with these undelivered messages:
+
+
+ Delayed redelivery.
+ It is possible to delay messages redelivery to let the client some time to recover
+ from transient failures and not overload its network or CPU resources
+
+
+ Dead Letter Address.
+ It is also possible to configure a dead letter address so that after a specified
+ number of unsuccessful deliveries, messages are removed from the queue and will not be
+ delivered again
+
+
+ Both options can be combined for maximum flexibility.
+
+ Delayed Redelivery
+ Delaying redelivery can often be useful in the case that clients regularly fail or
+ rollback. Without a delayed redelivery, the system can get into a "thrashing" state, with
+ delivery being attempted, the client rolling back, and delivery being re-attempted ad
+ infinitum in quick succession, consuming valuable CPU and network resources.
+
+ Configuring Delayed Redelivery
+ Delayed redelivery is defined in the address-setting configuration:
+
+<!-- delay redelivery of messages for 5s -->
+<address-setting match="jms.queue.exampleQueue">
+ <!-- default is 1.0 -->
+ <redelivery-delay-multiplier>1.5</redelivery-delay-multiplier>
+ <!-- default is 0 (no delay) -->
+ <redelivery-delay>5000</redelivery-delay>
+ <!-- default is redelivery-delay * 10 -->
+ <max-redelivery-delay>50000</max-redelivery-delay>
+
+</address-setting>
+ If a redelivery-delay is specified, HornetQ will wait this delay
+ before redelivering the messages.
+ By default, there is no redelivery delay (redelivery-delayis set
+ to 0).
+ Other subsequent messages will be delivery regularly, only the cancelled message
+ will be sent asynchronously back to the queue after the delay.
+ You can specify a multiplier that will take effect on top of the redelivery-delay
+ with a max-redelivery-delay to be taken into account.
+ The max-redelivery-delay is defaulted to redelivery-delay * 10
+ Address wildcards can be used to configure redelivery delay for a set of addresses
+ (see ), so you don't have to specify redelivery delay
+ individually for each address.
+
+
+ Example
+ See for an example which shows how
+ delayed redelivery is configured and used with JMS.
+
+
+
+ Dead Letter Addresses
+ To prevent a client infinitely receiving the same undelivered message (regardless of
+ what is causing the unsuccessful deliveries), messaging systems define dead letter addresses: after a specified unsuccessful delivery
+ attempts, the message is removed from the queue and send instead to a dead letter address.
+ Any such messages can then be diverted to queue(s) where they can later be perused by
+ the system administrator for action to be taken.
+ HornetQ's addresses can be assigned a dead letter address. Once the messages have been
+ unsuccessfully delivered for a given number of attempts, they are removed from the queue
+ and sent to the dead letter address. These dead letter messages can
+ later be consumed for further inspection.
+
+ Configuring Dead Letter Addresses
+ Dead letter address is defined in the address-setting configuration:
+
+<!-- undelivered messages in exampleQueue will be sent to the dead letter address
+ deadLetterQueue after 3 unsuccessful delivery attempts -->
+<address-setting match="jms.queue.exampleQueue">
+ <dead-letter-address>jms.queue.deadLetterQueue</dead-letter-address>
+ <max-delivery-attempts>3</max-delivery-attempts>
+</address-setting>
+ If a dead-letter-address is not specified, messages will removed
+ after max-delivery-attempts unsuccessful attempts.
+ By default, messages are redelivered 10 times at the maximum. Set max-delivery-attempts to -1 for infinite redeliveries.
+ For example, a dead letter can be set globally for a set of matching addresses and
+ you can set max-delivery-attempts to -1 for a specific address
+ setting to allow infinite redeliveries only for this address.
+ Address wildcards can be used to configure dead letter settings for a set of
+ addresses (see ).
+
+
+ Dead Letter Properties
+ Dead letter messages which are consumed from a dead letter address have the following
+ properties:
+
+
+ _HQ_ORIG_ADDRESS
+ a String property containing the original address of
+ the dead letter message
+
+
+ _HQ_ORIG_QUEUE
+ a String property containing the original queue of
+ the dead letter message
+
+
+
+
+ Example
+ See for an example which shows how dead letter
+ is configured and used with JMS.
+
+
+
+ Delivery Count Persistence
+ In normal use, HornetQ does not update delivery count persistently
+ until a message is rolled back (i.e. the delivery count is not updated
+ before the message is delivered to the consumer). In most messaging
+ use cases, the messages are consumed, acknowledged and forgotten as soon as they are
+ consumed. In these cases, updating the delivery count persistently before delivering the
+ message would add an extra persistent step for each message delivered,
+ implying a significant performance penalty.
+ However, if the delivery count is not updated persistently before the message delivery
+ happens, in the event of a server crash, messages might have been delivered but that will
+ not have been reflected in the delivery count. During the recovery phase, the server will
+ not have knowledge of that and will deliver the message with redelivered
+ set to false while it should be true.
+ As this behavior breaks strict JMS semantics, HornetQ allows to persist delivery count
+ before message delivery but disabled it by default for performance implications.
+ To enable it, set persist-delivery-count-before-delivery to true in hornetq-configuration.xml:
+
+<persist-delivery-count-before-delivery>true</persist-delivery-count-before-delivery>
+
+
diff --git a/docs/user-manual/en/using-core.xml b/docs/user-manual/en/using-core.xml
new file mode 100644
index 0000000000..eb72c79d3b
--- /dev/null
+++ b/docs/user-manual/en/using-core.xml
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Using Core
+ HornetQ core is a completely JMS-agnostic messaging system with its own non-JMS API. We
+ call this the core API.
+ If you don't want to use JMS you can use the core API directly. The core API provides all
+ the functionality of JMS but without much of the complexity. It also provides features that
+ are not available using JMS.
+
+ Core Messaging Concepts
+ Some of the core messaging concepts are similar to JMS concepts, but core messaging
+ concepts differ in some ways. In general the core messaging API is simpler than the JMS
+ API, since we remove distinctions between queues, topics and subscriptions. We'll
+ discuss each of the major core messaging concepts in turn, but to see the API in detail,
+ please consult the Javadoc.
+
+ Message
+
+
+ A message is the unit of data which is sent between clients and
+ servers.
+
+
+ A message has a body which is a buffer containing convenient methods for
+ reading and writing data into it.
+
+
+ A message has a set of properties which are key-value pairs. Each property
+ key is a string and property values can be of type integer, long, short,
+ byte, byte[], String, double, float or boolean.
+
+
+ A message has an address it is being sent to. When
+ the message arrives on the server it is routed to any queues that are bound
+ to the address - if the queues are bound with any filter, the message will
+ only be routed to that queue if the filter matches. An address may have many
+ queues bound to it or even none. There may also be entities other than
+ queues, like diverts bound to
+ addresses.
+
+
+ Messages can be either durable or non durable. Durable messages in a
+ durable queue will survive a server crash or restart. Non durable messages
+ will never survive a server crash or restart.
+
+
+ Messages can be specified with a priority value between 0 and 9. 0
+ represents the lowest priority and 9 represents the highest. HornetQ will
+ attempt to deliver higher priority messages before lower priority
+ ones.
+
+
+ Messages can be specified with an optional expiry time. HornetQ will not
+ deliver messages after its expiry time has been exceeded.
+
+
+ Messages also have an optional timestamp which represents the time the
+ message was sent.
+
+
+ HornetQ also supports the sending/consuming of very large messages - much
+ larger than can fit in available RAM at any one time.
+
+
+
+
+ Address
+ A server maintains a mapping between an address and a set of queues. Zero or more
+ queues can be bound to a single address. Each queue can be bound with an optional
+ message filter. When a message is routed, it is routed to the set of queues bound to
+ the message's address. If any of the queues are bound with a filter expression, then
+ the message will only be routed to the subset of bound queues which match that
+ filter expression.
+ Other entities, such as diverts can also be
+ bound to an address and messages will also be routed there.
+
+ In core, there is no concept of a Topic, Topic is a JMS only term. Instead, in
+ core, we just deal with addresses and
+ queues.
+ For example, a JMS topic would be implemented by a single address to which
+ many queues are bound. Each queue represents a subscription of the topic. A JMS
+ Queue would be implemented as a single address to which one queue is bound -
+ that queue represents the JMS queue.
+
+
+
+ Queue
+ Queues can be durable, meaning the messages they contain survive a server crash or
+ restart, as long as the messages in them are durable. Non durable queues do not
+ survive a server restart or crash even if the messages they contain are
+ durable.
+ Queues can also be temporary, meaning they are automatically deleted when the
+ client connection is closed, if they are not explicitly deleted before that.
+ Queues can be bound with an optional filter expression. If a filter expression is
+ supplied then the server will only route messages that match that filter expression
+ to any queues bound to the address.
+ Many queues can be bound to a single address. A particular queue is only bound to
+ a maximum of one address.
+
+
+ ServerLocator
+ Clients use ServerLocator instances to create ClientSessionFactory instances. ServerLocator
+ instances are used to locate servers and create connections to them.
+ In JMS terms think of a ServerLocator in the same way you would
+ a JMS Connection Factory.
+ ServerLocator instances are created using the HornetQClient factory class.
+
+
+ ClientSessionFactory
+ Clients use ClientSessionFactory instances to create ClientSession instances. ClientSessionFactory
+ instances are basically the connection to a server
+ In JMS terms think of them as JMS Connections.
+ ClientSessionFactory instances are created using the ServerLocator class.
+
+
+ ClientSession
+ A client uses a ClientSession for consuming and producing messages and for
+ grouping them in transactions. ClientSession instances can support both
+ transactional and non transactional semantics and also provide an XAResource interface so messaging operations can be performed as part
+ of a JTA
+ transaction.
+ ClientSession instances group ClientConsumers and ClientProducers.
+ ClientSession instances can be registered with an optional SendAcknowledgementHandler. This allows your client code to be
+ notified asynchronously when sent messages have successfully reached the server.
+ This unique HornetQ feature, allows you to have full guarantees that sent messages
+ have reached the server without having to block on each message sent until a
+ response is received. Blocking on each messages sent is costly since it requires a
+ network round trip for each message sent. By not blocking and receiving send
+ acknowledgements asynchronously you can create true end to end asynchronous systems
+ which is not possible using the standard JMS API. For more information on this
+ advanced feature please see the section .
+
+
+ ClientConsumer
+ Clients use ClientConsumer instances to consume messages from a
+ queue. Core Messaging supports both synchronous and asynchronous message consumption
+ semantics. ClientConsumer instances can be configured with an
+ optional filter expression and will only consume messages which match that
+ expression.
+
+
+ ClientProducer
+ Clients create ClientProducer instances on ClientSession instances so they can send messages. ClientProducer
+ instances can specify an address to which all sent messages are routed, or they can
+ have no specified address, and the address is specified at send time for the
+ message.
+
+
+ Please note that ClientSession, ClientProducer and ClientConsumer instances are
+ designed to be re-used.
+ It's an anti-pattern to create new ClientSession, ClientProducer and
+ ClientConsumer instances for each message you produce or consume. If you do this,
+ your application will perform very poorly. This is discussed further in the section
+ on performance tuning .
+
+
+
+ A simple example of using Core
+ Here's a very simple program using the core messaging API to send and receive a
+ message:
+
+ServerLocator locator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(
+ InVMConnectorFactory.class.getName()));
+
+ClientSessionFactory factory = locator.createClientSessionFactory();
+
+ClientSession session = factory.createSession();
+
+session.createQueue("example", "example", true);
+
+ClientProducer producer = session.createProducer("example");
+
+ClientMessage message = session.createMessage(true);
+
+message.getBodyBuffer().writeString("Hello");
+
+producer.send(message);
+
+session.start();
+
+ClientConsumer consumer = session.createConsumer("example");
+
+ClientMessage msgReceived = consumer.receive();
+
+System.out.println("message = " + msgReceived.getBodyBuffer().readString());
+
+session.close();
+
+
diff --git a/docs/user-manual/en/using-jms.xml b/docs/user-manual/en/using-jms.xml
new file mode 100644
index 0000000000..aaecf62594
--- /dev/null
+++ b/docs/user-manual/en/using-jms.xml
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Using JMS
+ Although HornetQ provides a JMS agnostic messaging API, many users will be more
+ comfortable using JMS.
+ JMS is a very popular API standard for messaging, and most messaging systems provide a JMS
+ API. If you are completely new to JMS we suggest you follow the Sun
+ JMS tutorial - a full JMS tutorial is out of scope for this guide.
+ HornetQ also ships with a wide range of examples, many of which demonstrate JMS API usage.
+ A good place to start would be to play around with the simple JMS Queue and Topic example,
+ but we also provide examples for many other parts of the JMS API. A full description of the
+ examples is available in .
+ In this section we'll go through the main steps in configuring the server for JMS and
+ creating a simple JMS program. We'll also show how to configure and use JNDI, and also how
+ to use JMS with HornetQ without using any JNDI.
+
+ A simple ordering system
+ For this chapter we're going to use a very simple ordering system as our example. It is
+ a somewhat contrived example because of its extreme simplicity, but it serves to
+ demonstrate the very basics of setting up and using JMS.
+ We will have a single JMS Queue called OrderQueue, and we will have
+ a single MessageProducer sending an order message to the queue and a
+ single MessageConsumer consuming the order message from the
+ queue.
+ The queue will be a durable queue, i.e. it will survive a server
+ restart or crash. We also want to pre-deploy the queue, i.e. specify the queue in the
+ server JMS configuration so it is created automatically without us having to explicitly
+ create it from the client.
+
+
+ JMS Server Configuration
+ The file hornetq-jms.xml on the server classpath contains any JMS
+ Queue, Topic and ConnectionFactory instances that we wish to create and make available
+ to lookup via the JNDI.
+ A JMS ConnectionFactory object is used by the client to make connections to the
+ server. It knows the location of the server it is connecting to, as well as many other
+ configuration parameters. In most cases the defaults will be acceptable.
+ We'll deploy a single JMS Queue and a single JMS Connection Factory instance on the
+ server for this example but there are no limits to the number of Queues, Topics and
+ Connection Factory instances you can deploy from the file. Here's our
+ configuration:
+
+<configuration xmlns="urn:hornetq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:hornetq ../schemas/hornetq-jms.xsd ">
+
+ <connection-factory name="ConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ </connection-factory>
+
+ <queue name="OrderQueue">
+ <entry name="queues/OrderQueue"/>
+ </queue>
+</configuration>
+ We deploy one ConnectionFactory called ConnectionFactory and bind
+ it in just one place in JNDI as given by the entry element.
+ ConnectionFactory instances can be bound in many places in JNDI if you require.
+
+ The JMS connection factory references a connector called
+ netty. This is a reference to a connector object deployed in
+ the main core configuration file hornetq-configuration.xml which
+ defines the transport and parameters used to actually connect to the server.
+
+
+
+ Connection Factory Types
+ The JMS API doc provides several connection factories for applications. HornetQ JMS users
+ can choose to configure the types for their connection factories. Each connection factory
+ has a signature attribute and a xa parameter, the
+ combination of which determines the type of the factory. Attribute signature
+ has three possible string values, i.e. generic,
+ queue and topic; xa is a boolean
+ type parameter. The following table gives their configuration values for different
+ connection factory interfaces.
+
+ As an example, the following configures an XAQueueConnectionFactory:
+
+<configuration xmlns="urn:hornetq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:hornetq ../schemas/hornetq-jms.xsd ">
+
+ <connection-factory name="ConnectionFactory" signature="queue">
+ <xa>true</xa>
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="ConnectionFactory"/>
+ </entries>
+ </connection-factory>
+</configuration>
+
+
+
+ JNDI configuration
+ When using JNDI from the client side you need to specify a set of JNDI properties
+ which tell the JNDI client where to locate the JNDI server, amongst other things. These
+ are often specified in a file called jndi.properties on the client
+ classpath, or you can specify them directly when creating the JNDI initial context. A
+ full JNDI tutorial is outside the scope of this document, please see the Sun JNDI tutorial
+ for more information on how to use JNDI.
+ For talking to the JBoss JNDI Server, the jndi properties will look something like
+ this:
+
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://myhost:1099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
+ Where myhost is the hostname or IP address of the JNDI server. 1099
+ is the port used by the JNDI server and may vary depending on how you have configured
+ your JNDI server.
+ In the default standalone configuration, JNDI server ports are configured in the file
+ hornetq-beans.xml by setting properties on the JNDIServer bean:
+
+<bean name="StandaloneServer" class="org.hornetq.jms.server.impl.StandaloneNamingServer">
+ <constructor>
+ <parameter>
+ <inject bean="HornetQServer"/>
+ </parameter>
+ </constructor>
+ <property name="port">${jnp.port:1099}</property>
+ <property name="bindAddress">${jnp.host:localhost}</property>
+ <property name="rmiPort">${jnp.rmiPort:1098}</property>
+ <property name="rmiBindAddress">${jnp.host:localhost}</property>
+</bean>
+
+ If you want your JNDI server to be available to non local clients make sure you
+ change its bind address to something other than localhost!
+
+
+ The JNDIServer bean must be defined only when HornetQ is running in
+ stand-alone mode. When HornetQ is integrated to JBoss Application
+ Server, JBoss AS will provide a ready-to-use JNDI server without any additional
+ configuration.
+
+
+
+ The code
+ Here's the code for the example:
+ First we'll create a JNDI initial context from which to lookup our JMS objects:
+ InitialContext ic = new InitialContext();
+ Now we'll look up the connection factory:
+ ConnectionFactory cf = (ConnectionFactory)ic.lookup("/ConnectionFactory");
+ And look up the Queue:
+ Queue orderQueue = (Queue)ic.lookup("/queues/OrderQueue");
+ Next we create a JMS connection using the connection factory:
+ Connection connection = cf.createConnection();
+ And we create a non transacted JMS Session, with AUTO_ACKNOWLEDGE acknowledge
+ mode:
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ We create a MessageProducer that will send orders to the queue:
+ MessageProducer producer = session.createProducer(orderQueue);
+ And we create a MessageConsumer which will consume orders from the queue:
+ MessageConsumer consumer = session.createConsumer(orderQueue);
+ We make sure we start the connection, or delivery won't occur on it:
+ connection.start();
+ We create a simple TextMessage and send it:
+ TextMessage message = session.createTextMessage("This is an order");
+producer.send(message);
+ And we consume the message:
+ TextMessage receivedMessage = (TextMessage)consumer.receive();
+System.out.println("Got order: " + receivedMessage.getText());
+ It is as simple as that. For a wide range of working JMS examples please see the
+ examples directory in the distribution.
+
+ Please note that JMS connections, sessions, producers and consumers are
+ designed to be re-used.
+ It is an anti-pattern to create new connections, sessions, producers and consumers
+ for each message you produce or consume. If you do this, your application will
+ perform very poorly. This is discussed further in the section on performance tuning
+ .
+
+
+
+ Directly instantiating JMS Resources without using JNDI
+ Although it is a very common JMS usage pattern to lookup JMS Administered
+ Objects (that's JMS Queue, Topic and ConnectionFactory instances) from
+ JNDI, in some cases a JNDI server is not available and you still want to use JMS, or you
+ just think "Why do I need JNDI? Why can't I just instantiate these objects
+ directly?"
+ With HornetQ you can do exactly that. HornetQ supports the direct instantiation of JMS
+ Queue, Topic and ConnectionFactory instances, so you don't have to use JNDI at
+ all.
+ For a full working example of direct instantiation please see the JMS examples in
+ .
+ Here's our simple example, rewritten to not use JNDI at all:
+ We create the JMS ConnectionFactory object via the HornetQJMSClient Utility class,
+ note we need to provide connection parameters and specify which transport we are using,
+ for more information on connectors please see .
+
+TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName());
+ConnectionFactory cf = HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF,transportConfiguration);
+ We also create the JMS Queue object via the HornetQJMSClient Utility class:
+ Queue orderQueue = HornetQJMSClient.createQueue("OrderQueue");
+ Next we create a JMS connection using the connection factory:
+ Connection connection = cf.createConnection();
+ And we create a non transacted JMS Session, with AUTO_ACKNOWLEDGE acknowledge
+ mode:
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ We create a MessageProducer that will send orders to the queue:
+ MessageProducer producer = session.createProducer(orderQueue);
+ And we create a MessageConsumer which will consume orders from the queue:
+ MessageConsumer consumer = session.createConsumer(orderQueue);
+ We make sure we start the connection, or delivery won't occur on it:
+ connection.start();
+ We create a simple TextMessage and send it:
+ TextMessage message = session.createTextMessage("This is an order");
+producer.send(message);
+ And we consume the message:
+ TextMessage receivedMessage = (TextMessage)consumer.receive();
+System.out.println("Got order: " + receivedMessage.getText());
+
+
+ Setting The Client ID
+ This represents the client id for a JMS client and is needed for creating durable
+ subscriptions. It is possible to configure this on the connection factory and can be set
+ via the client-id element. Any connection created by this connection
+ factory will have this set as its client id.
+
+
+ Setting The Batch Size for DUPS_OK
+ When the JMS acknowledge mode is set to DUPS_OK it is possible to
+ configure the consumer so that it sends acknowledgements in batches rather that one at a
+ time, saving valuable bandwidth. This can be configured via the connection factory via
+ the dups-ok-batch-size element and is set in bytes. The default is
+ 1024 * 1024 bytes = 1 MiB.
+
+
+ Setting The Transaction Batch Size
+ When receiving messages in a transaction it is possible to configure the consumer to
+ send acknowledgements in batches rather than individually saving valuable bandwidth.
+ This can be configured on the connection factory via the transaction-batch-size element and is set in bytes. The default is 1024 *
+ 1024.
+
+
diff --git a/docs/user-manual/en/using-server.xml b/docs/user-manual/en/using-server.xml
new file mode 100644
index 0000000000..c5f12657f7
--- /dev/null
+++ b/docs/user-manual/en/using-server.xml
@@ -0,0 +1,385 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+ Using the Server
+ This chapter will familiarise you with how to use the HornetQ server.
+ We'll show where it is, how to start and stop it, and we'll describe the directory layout
+ and what all the files are and what they do.
+ For the remainder of this chapter when we talk about the HornetQ server we mean the
+ HornetQ standalone server, in its default configuration with a JMS Service and JNDI service
+ enabled.
+ When running embedded in JBoss Application Server the layout may be slightly different but
+ by-and-large will be the same.
+
+ Starting and Stopping the standalone server
+ In the distribution you will find a directory called bin.
+ cd into that directory and you will find a Unix/Linux script called
+ run.sh and a windows batch file called run.bat
+ To run on Unix/Linux type ./run.sh
+ To run on Windows type run.bat
+ These scripts are very simple and basically just set-up the classpath and some JVM
+ parameters and start the JBoss Microcontainer. The Microcontainer is a light weight
+ container used to deploy the HornetQ POJO's
+ To stop the server you will also find a Unix/Linux script stop.sh and
+ a windows batch file stop.bat
+ To run on Unix/Linux type ./stop.sh
+ To run on Windows type stop.bat
+ Please note that HornetQ requires a Java 6 or later runtime to run.
+ Both the run and the stop scripts use the config under config/stand-alone/non-clustered by default. The configuration can be
+ changed by running ./run.sh ../config/stand-alone/clustered or
+ another config of your choosing. This is the same for the stop script and the windows
+ bat files.
+
+
+ Server JVM settings
+ The run scripts run.sh and run.bat set some JVM
+ settings for tuning running on Java 6 and choosing the garbage collection policy. We
+ recommend using a parallel garbage collection algorithm to smooth out latency and
+ minimise large GC pauses.
+ By default HornetQ runs in a maximum of 1GiB of RAM. To increase the memory settings
+ change the -Xms and -Xmx memory settings as you
+ would for any Java program.
+ If you wish to add any more JVM arguments or tune the existing ones, the run scripts
+ are the place to do it.
+
+
+ Server classpath
+ HornetQ looks for its configuration files on the Java classpath.
+ The scripts run.sh and run.bat specify the
+ classpath when calling Java to run the server.
+ In the distribution, the run scripts will add the non clustered configuration
+ directory to the classpath. This is a directory which contains a set of configuration
+ files for running the HornetQ server in a basic non-clustered configuration. In the
+ distribution this directory is config/stand-alone/non-clustered/ from
+ the root of the distribution.
+ The distribution contains several standard configuration sets for running:
+
+
+ Non clustered stand-alone.
+
+
+ Clustered stand-alone
+
+
+ Non clustered in JBoss Application Server
+
+
+ Clustered in JBoss Application Server
+
+
+ You can of course create your own configuration and specify any configuration
+ directory when running the run script.
+ Just make sure the directory is on the classpath and HornetQ will search there when
+ starting up.
+
+
+ Library Path
+ If you're using the Asynchronous IO Journal on
+ Linux, you need to specify java.library.path as a property on your
+ Java options. This is done automatically in the run.sh script.
+ If you don't specify java.library.path at your Java options then
+ the JVM will use the environment variable LD_LIBRARY_PATH.
+
+
+ System properties
+ HornetQ can take a system property on the command line for configuring logging.
+ For more information on configuring logging, please see .
+
+
+ Configuration files
+ The configuration directory is specified on the classpath in the run scripts run.sh and run.bat This directory can contain the
+ following files.
+
+
+ hornetq-beans.xml (or hornetq-jboss-beans.xml if you're running inside JBoss
+ Application Server). This is the JBoss Microcontainer beans file which defines
+ what beans the Microcontainer should create and what dependencies to enforce
+ between them. Remember that HornetQ is just a set of POJOs. In the stand-alone
+ server, it's the JBoss Microcontainer which instantiates these POJOs and
+ enforces dependencies between them and other beans.
+
+
+ hornetq-configuration.xml. This is the main HornetQ
+ configuration file. All the parameters in this file are described in . Please see for more information on this file.
+
+
+ hornetq-queues.xml. This file contains predefined queues,
+ queue settings and security settings. The file is optional - all this
+ configuration can also live in hornetq-configuration.xml. In
+ fact, the default configuration sets do not have a hornetq-queues.xml file. The purpose of allowing queues to be
+ configured in these files is to allow you to manage your queue configuration
+ over many files instead of being forced to maintain it in a single file. There
+ can be many hornetq-queues.xml files on the classpath. All
+ will be loaded if found.
+
+
+ hornetq-users.xml HornetQ ships with a basic security
+ manager implementation which obtains user credentials from the hornetq-users.xml file. This file contains user, password and
+ role information. For more information on security, please see .
+
+
+ hornetq-jms.xml The distro configuration by default
+ includes a server side JMS service which mainly deploys JMS Queues, Topics and
+ ConnectionFactorys from this file into JNDI. If you're not using JMS, or you
+ don't need to deploy JMS objects on the server side, then you don't need this
+ file. For more information on using JMS, please see .
+
+
+ logging.properties This is used to configure the logging
+ handlers used by the Java logger. For more information on configuring logging,
+ please see .
+
+
+
+ The property file-deployment-enabled in the hornetq-configuration.xml configuration when set to false means that
+ the other configuration files are not loaded. This is true by default.
+
+ It is also possible to use system property substitution in all the configuration
+ files. by replacing a value with the name of a system property. Here is an example of
+ this with a connector configuration:
+
+<connector name="netty">
+ <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
+ <param key="host" value="${hornetq.remoting.netty.host:localhost}"/>
+ <param key="port" value="${hornetq.remoting.netty.port:5445}"/>
+</connector>
+ Here you can see we have replaced 2 values with system properties hornetq.remoting.netty.host and hornetq.remoting.netty.port. These values will be replaced by the value
+ found in the system property if there is one, if not they default back to localhost or
+ 5445 respectively. It is also possible to not supply a default. i.e. ${hornetq.remoting.netty.host}, however the system property
+ must be supplied in that case.
+
+
+ JBoss Microcontainer Beans File
+ The stand-alone server is basically a set of POJOs which are instantiated by the light
+ weight JBoss Microcontainer
+ engine.
+
+ A beans file is also needed when the server is deployed in the JBoss Application
+ Server but this will deploy a slightly different set of objects since the
+ Application Server will already have things like security etc deployed.
+
+ Let's take a look at an example beans file from the stand-alone server:
+
+
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- MBean server -->
+ <bean name="MBeanServer" class="javax.management.MBeanServer">
+ <constructor factoryClass="java.lang.management.ManagementFactory"
+ factoryMethod="getPlatformMBeanServer"/>
+ </bean>
+
+ <!-- The core configuration -->
+ <bean name="Configuration" class="org.hornetq.core.config.impl.FileConfiguration">
+ </bean>
+
+ <!-- The security manager -->
+ <bean name="HornetQSecurityManager" class="org.hornetq.spi.core.security.HornetQSecurityManagerImpl">
+ <start ignored="true"/>
+ <stop ignored="true"/>
+ </bean>
+
+ <!-- The core server -->
+ <bean name="HornetQServer" class="org.hornetq.core.server.impl.HornetQServerImpl">
+ <constructor>
+ <parameter>
+ <inject bean="Configuration"/>
+ </parameter>
+ <parameter>
+ <inject bean="MBeanServer"/>
+ </parameter>
+ <parameter>
+ <inject bean="HornetQSecurityManager"/>
+ </parameter>
+ </constructor>
+ <start ignored="true"/>
+ <stop ignored="true"/>
+ </bean>
+
+ <!-- The Stand alone server that controls the jndi server-->
+ <bean name="StandaloneServer" class="org.hornetq.jms.server.impl.StandaloneNamingServer">
+ <constructor>
+ <parameter>
+ <inject bean="HornetQServer"/>
+ </parameter>
+ </constructor>
+ <property name="port">${jnp.port:1099}</property>
+ <property name="bindAddress">${jnp.host:localhost}</property>
+ <property name="rmiPort">${jnp.rmiPort:1098}</property>
+ <property name="rmiBindAddress">${jnp.host:localhost}</property>
+ </bean>
+
+ <!-- The JMS server -->
+ <bean name="JMSServerManager" class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
+ <constructor>
+ <parameter>
+ <inject bean="HornetQServer"/>
+ </parameter>
+ </constructor>
+ </bean>
+
+
+</deployment>
+
+ We can see that, as well as the core HornetQ server, the stand-alone server
+ instantiates various different POJOs, let's look at them in turn:
+
+
+ MBeanServer
+ In order to provide a JMX management interface a JMS MBean server is necessary
+ in which to register the management objects. Normally this is just the default
+ platform MBean server available in the JVM instance. If you don't want to
+ provide a JMX management interface this can be commented out or removed.
+
+
+ Configuration
+ The HornetQ server is configured with a Configuration object. In the default
+ stand-alone set-up it uses a FileConfiguration object which knows to read
+ configuration information from the file system. In different configurations such
+ as embedded you might want to provide configuration information from somewhere
+ else.
+
+
+ Security Manager. The security manager used by the messaging server is
+ pluggable. The default one used just reads user-role information from the
+ hornetq-users.xml file on disk. However it can be
+ replaced by a JAAS security manager, or when running inside JBoss Application
+ Server it can be configured to use the JBoss AS security manager for tight
+ integration with JBoss AS security. If you've disabled security altogether you
+ can remove this too.
+
+
+ HornetQServer
+ This is the core server. It's where 99% of the magic happens
+
+
+ StandaloneServer
+ Many clients like to look up JMS Objects from JNDI so we provide a JNDI server
+ for them to do that. This class is a wrapper around the JBoss naming server.
+ If you don't need JNDI this can be commented out or removed.
+
+
+ JMSServerManager
+ This deploys any JMS Objects such as JMS Queues, Topics and ConnectionFactory
+ instances from hornetq-jms.xml files on the disk. It also
+ provides a simple management API for manipulating JMS Objects. On the whole it
+ just translates and delegates its work to the core server. If you don't need to
+ deploy JMS Queues, Topics and ConnectionFactorys from server side configuration
+ and don't require the JMS management interface this can be disabled.
+
+
+
+
+ JBoss AS4 MBean Service.
+
+ The section is only to configure HornetQ on JBoss AS4. The service functionality is
+ similar to Microcontainer Beans
+
+
+
+<?xml version="1.0" encoding="UTF-8"?>
+<server>
+ <mbean code="org.hornetq.service.HornetQFileConfigurationService"
+ name="org.hornetq:service=HornetQFileConfigurationService">
+ </mbean>
+
+ <mbean code="org.hornetq.service.JBossASSecurityManagerService"
+ name="org.hornetq:service=JBossASSecurityManagerService">
+ </mbean>
+
+ <mbean code="org.hornetq.service.HornetQStarterService"
+ name="org.hornetq:service=HornetQStarterService">
+ <!--let's let the JMS Server start us-->
+ <attribute name="Start">false</attribute>
+
+ <depends optional-attribute-name="SecurityManagerService"
+ proxy-type="attribute">org.hornetq:service=JBossASSecurityManagerService</depends>
+ <depends optional-attribute-name="ConfigurationService"
+ proxy-type="attribute">org.hornetq:service=HornetQFileConfigurationService</depends>
+ </mbean>
+
+ <mbean code="org.hornetq.service.HornetQJMSStarterService"
+ name="org.hornetq:service=HornetQJMSStarterService">
+ <depends optional-attribute-name="HornetQServer"
+ proxy-type="attribute">org.hornetq:service=HornetQStarterService</depends>
+ </mbean>
+</server>
+
+ This jboss-service.xml configuration file is included inside the hornetq-service.sar
+ on AS4 with embedded HornetQ. As you can see, on this configuration file we are starting
+ various services:
+
+
+ HornetQFileConfigurationService
+ This is an MBean Service that takes care of the life cycle of the FileConfiguration POJO
+
+
+ JBossASSecurityManagerService
+ This is an MBean Service that takes care of the lifecycle of the JBossASSecurityManager POJO
+
+
+ HornetQStarterService
+ This is an MBean Service that controls the main HornetQServer POJO.
+ this has a dependency on JBossASSecurityManagerService and HornetQFileConfigurationService MBeans
+
+
+ HornetQJMSStarterService
+ This is an MBean Service that controls the JMSServerManagerImpl POJO.
+ If you aren't using jms this can be removed.
+
+
+ JMSServerManager
+ Has the responsibility to start the JMSServerManager and the same behaviour that JMSServerManager Bean
+
+
+
+
+ The main configuration file.
+ The configuration for the HornetQ core server is contained in hornetq-configuration.xml. This is what the FileConfiguration bean uses
+ to configure the messaging server.
+ There are many attributes which you can configure HornetQ. In most cases the defaults
+ will do fine, in fact every attribute can be defaulted which means a file with a single
+ empty configuration element is a valid configuration file. The
+ different configuration will be explained throughout the manual or you can refer to the
+ configuration reference here.
+
+
diff --git a/docs/user-manual/en/vertx-integration.xml b/docs/user-manual/en/vertx-integration.xml
new file mode 100644
index 0000000000..71bb11023a
--- /dev/null
+++ b/docs/user-manual/en/vertx-integration.xml
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %BOOK_ENTITIES;
+ ]>
+
+ Vert.x Integration
+ Vert.x is a lightweight, high performance application platform for the
+ JVM that's designed for modern mobile, web, and enterprise applications. Vert.x provides a distributed event bus that
+ allows messages to be sent across vert.x instances and clients. You can now redirect and persist any vert.x messages
+ to HornetQ and route those messages to a specified vertx address by configuring HornetQ vertx incoming and outgoing
+ vertx connector services.
+
+
+
+ Configuring a Vertx Incoming Connector Service
+ Vertx Incoming Connector services receive messages from vertx event bus and route them to a HornetQ queue.
+ Such a service can be configured as follows:
+
+ <connector-service name="vertx-incoming-connector">
+ <factory-class>org.hornetq.integration.vertx.VertxIncomingConnectorServiceFactory</factory-class>
+ <param key="host" value="127.0.0.1"/>
+ <param key="port" value="0"/>
+ <param key="queue" value="jms.queue.vertxQueue"/>
+ <param key="vertx-address" value="vertx.in.eventaddress"/>
+ </connector-service>
+
+ Shown are the required params for the connector service:
+
+
+ queue. The name of the HornetQ queue to send message to.
+
+
+ As well as these required paramaters there are the following optional parameters
+
+
+ host. The host name on which the vertx target container is running. Default is localhost.
+
+
+ port. The port number to which the target vertx listens. Default is zero.
+
+
+ quorum-size. The quorum size of the target vertx instance.
+
+
+ ha-group. The name of the ha-group of target vertx instance. Default is hornetq.
+
+
+ vertx-address. The vertx address to listen to. default is org.hornetq.
+
+
+
+
+
+ Configuring a Vertx Outgoing Connector Service
+ Vertx Outgoing Connector services fetch vertx messages from a HornetQ queue and put them to vertx event bus.
+ Such a service can be configured as follows:
+
+ <connector-service name="vertx-outgoing-connector">
+ <factory-class>org.hornetq.integration.vertx.VertxOutgoingConnectorServiceFactory</factory-class>
+ <param key="host" value="127.0.0.1"/>
+ <param key="port" value="0"/>
+ <param key="queue" value="jms.queue.vertxQueue"/>
+ <param key="vertx-address" value="vertx.out.eventaddress"/>
+ <param key="publish" value="true"/>
+ </connector-service>
+
+ Shown are the required params for the connector service:
+
+
+ queue. The name of the HornetQ queue to fetch message from.
+
+
+ As well as these required paramaters there are the following optional parameters
+
+
+ host. The host name on which the vertx target container is running. Default is localhost.
+
+
+ port. The port number to which the target vertx listens. Default is zero.
+
+
+ quorum-size. The quorum size of the target vertx instance.
+
+
+ ha-group. The name of the ha-group of target vertx instance. Default is hornetq.
+
+
+ vertx-address. The vertx address to put messages to. default is org.hornetq.
+
+
+ publish. How messages is sent to vertx event bus. "true" means using publish style.
+ "false" means using send style. Default is false.
+
+
+
+
diff --git a/docs/user-manual/en/wildcard-routing.xml b/docs/user-manual/en/wildcard-routing.xml
new file mode 100644
index 0000000000..44f0f75953
--- /dev/null
+++ b/docs/user-manual/en/wildcard-routing.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+
+ Routing Messages With Wild Cards
+ HornetQ allows the routing of messages via wildcard addresses.
+ If a queue is created with an address of say queue.news.# then it
+ will receive any messages sent to addresses that match this, for instance queue.news.europe or queue.news.usa or queue.news.usa.sport. If you create a consumer on this queue, this allows a consumer to consume messages which are
+ sent to a hierarchy of addresses.
+
+ In JMS terminology this allows "topic hierarchies" to be created.
+
+ To enable this functionality set the property wild-card-routing-enabled
+ in the hornetq-configuration.xml file to true. This is
+ true by default.
+ For more information on the wild card syntax take a look at chapter, also see .
+
diff --git a/docs/user-manual/en/wildcard-syntax.xml b/docs/user-manual/en/wildcard-syntax.xml
new file mode 100644
index 0000000000..b121eb5531
--- /dev/null
+++ b/docs/user-manual/en/wildcard-syntax.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%BOOK_ENTITIES;
+]>
+
+
+ Understanding the HornetQ Wildcard Syntax
+ HornetQ uses a specific syntax for representing wildcards in security settings,
+ address settings and when creating consumers.
+ The syntax is similar to that used by AMQP.
+ A HornetQ wildcard expression contains words delimited by the character '.' (full stop).
+ The special characters '#' and '*' also have special
+ meaning and can take the place of a word.
+ The character '#' means 'match any sequence of zero or more
+ words'.
+ The character '*' means 'match a single word'.
+ So the wildcard 'news.europe.#' would match 'news.europe', 'news.europe.sport',
+ 'news.europe.politics', and 'news.europe.politics.regional' but would not match 'news.usa',
+ 'news.usa.sport' nor 'entertainment'.
+ The wildcard 'news.*' would match 'news.europe', but not 'news.europe.sport'.
+ The wildcard 'news.*.sport' would match 'news.europe.sport' and also 'news.usa.sport', but
+ not 'news.europe.politics'.
+
diff --git a/docs/user-manual/pom.xml b/docs/user-manual/pom.xml
new file mode 100644
index 0000000000..549f6487f3
--- /dev/null
+++ b/docs/user-manual/pom.xml
@@ -0,0 +1,361 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.hornetq.docs
+ hornetq-docs
+ 2.5.0-SNAPSHOT
+
+
+ org.hornetq.docs
+ user-manual
+ 1.0
+ jdocbook
+ user-manual
+
+
+ en
+ HornetQ_User_Manual
+ HornetQ User Manual
+
+
+
+
+ jboss-public-repository-group
+ JBoss Public Maven Repository Group
+ https://repository.jboss.org/nexus/content/groups/public/
+ default
+
+ true
+ never
+
+
+ true
+ never
+
+
+
+
+
+ jboss-public-repository-group
+ JBoss Public Maven Repository Group
+ https://repository.jboss.org/nexus/content/groups/public/
+ default
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+ all
+
+ true
+
+
+
+
+ org.jboss.maven.plugins
+ maven-jdocbook-plugin
+ 2.3.5
+ true
+
+
+
+ pdf
+ classpath:/xslt/org/jboss/pdf.xsl
+ ${docname}.pdf
+
+
+ html
+ classpath:/xslt/org/jboss/xhtml.xsl
+ index.html
+
+
+ html_single
+ classpath:/xslt/org/jboss/xhtml-single.xsl
+ index.html
+
+
+
+
+
+
+
+
+
+
+ html
+
+ false
+
+
+
+
+ org.jboss.maven.plugins
+ maven-jdocbook-plugin
+ 2.2.1
+ true
+
+
+
+ html
+ classpath:/xslt/org/jboss/xhtml.xsl
+ index.html
+
+
+
+
+
+
+
+
+
+
+ html-single
+
+ false
+
+
+
+
+ org.jboss.maven.plugins
+ maven-jdocbook-plugin
+ 2.2.1
+ true
+
+
+
+
+
+
+
+ pdf
+
+ false
+
+
+
+
+ org.jboss.maven.plugins
+ maven-jdocbook-plugin
+ 2.2.1
+ true
+
+
+
+ pdf
+ classpath:/xslt/org/jboss/pdf.xsl
+ ${docname}.pdf
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.jboss.maven.plugins
+ maven-jdocbook-plugin
+ 2.2.1
+ true
+
+
+ org.jboss.pressgang
+ pressgang-xslt
+ 2.0.2
+
+
+ org.jboss
+ jbossorg-jdocbook-style
+ 1.1.1
+ jdocbook-style
+
+
+
+ ${project.basedir}
+ ${docname}.xml
+ en
+
+ ${project.basedir}/en
+
+ images/*.png
+ images/*.jpg
+
+
+
+
+ pdf
+ classpath:/xslt/org/jboss/pdf.xsl
+ ${pdf.name}
+
+
+ html
+ classpath:/xslt/org/jboss/xhtml.xsl
+ index.html
+
+
+ html_single
+ classpath:/xslt/org/jboss/xhtml-single.xsl
+ index.html
+
+
+
+ true
+ saxon
+ 1.72.0
+ -
+ false
+
+
+ javax.xml.parsers.DocumentBuilderFactory
+ org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
+
+
+ javax.xml.parsers.SAXParserFactory
+ org.apache.xerces.jaxp.SAXParserFactoryImpl
+
+
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ xml-maven-plugin
+
+
+
+ transform
+
+
+
+
+ net.sf.saxon.TransformerFactoryImpl
+
+
+ ../../hornetq-server/src/main/resources/schema
+ ./src/main/resources/schemaToTable.xsl
+
+ hornetq-configuration.xsd
+
+
+
+ .xml
+
+
+
+
+ ../../hornetq-jms-server/src/main/resources/schema
+ ./src/main/resources/schemaToTable.xsl
+
+ hornetq-jms.xsd
+
+
+
+ .xml
+
+
+
+
+
+
+
+ net.sf.saxon
+ saxon
+ 8.7
+
+
+
+
+
+
+
+
diff --git a/docs/user-manual/publican.cfg b/docs/user-manual/publican.cfg
new file mode 100644
index 0000000000..821b3484ee
--- /dev/null
+++ b/docs/user-manual/publican.cfg
@@ -0,0 +1,7 @@
+# Config::Simple 4.59
+# Tue Mar 29 06:11:07 2011
+
+xml_lang: en
+type: Book
+brand: common
+
diff --git a/docs/user-manual/src/main/resources/schemaToTable.xsl b/docs/user-manual/src/main/resources/schemaToTable.xsl
new file mode 100644
index 0000000000..1f5dedabaa
--- /dev/null
+++ b/docs/user-manual/src/main/resources/schemaToTable.xsl
@@ -0,0 +1,374 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ THIS IS A GENERATED FILE. DO NOT EDIT IT DIRECTLY!
+
+ HornetQ options reference table generated from:
+
+
+ =======================================================================
+
+ XSLT Version =
+ XSLT Vendor =
+ XSLT Vendor URL =
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
VALUE OF COMPLEX TYPE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Complex element
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (
+
+ required
+
+ attribute)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ELEMENT TEMPLATE name=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
E.NAME-ref name=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ELEMENT TYPE-ref TEMPLATE CHILDREN
+
+
+
+
+
+
+
+
+
+
+
+
ELEMENT REF TEMPLATE ref=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/user-manual/user-manual.xpr b/docs/user-manual/user-manual.xpr
new file mode 100644
index 0000000000..2f3e5ddfbd
--- /dev/null
+++ b/docs/user-manual/user-manual.xpr
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/user-manual/zh/appserver-integration.xml b/docs/user-manual/zh/appserver-integration.xml
new file mode 100644
index 0000000000..a77e810be8
--- /dev/null
+++ b/docs/user-manual/zh/appserver-integration.xml
@@ -0,0 +1,1001 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Java EE和应用服务器的集成
+ HornetQ可以容易地安装到JBoss 4应用服务器及其以上版本。有关安装的详细说明请参阅快速指南。
+ HornetQ提供了一个JCA适配器,使得它还可以与其它JEE兼容的应用服务器集成。请参阅其它应用服务器的
+ 有关JCA适配器集成的说明来操作。
+ JCA适配器的作用是控制消息流入到消息Bean(MDB),并控制消息从各种JEE模块中发出(如EJB和Servlet)。
+ 本章讲述这些JEE模块配置HornetQ的基本信息。
+
+ 配置消息Bean
+ 使用HornetQ向MDB传递消息,需要在文件ra.xml中配置JCA适配器。该文件在
+ jms-ra.rar文件中。默认配置下HornetQ服务使用InVm连接器接收消息。在本章
+ 后面列出了可配置的选项。
+ 所有MDB都需要有目标类型和目标的相关配置。下面就是一个使用annotation配置MDB的例子:
+ @MessageDriven(name = "MDBExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue")
+ })
+@ResourceAdapter("hornetq-ra.rar")
+public class MDBExample implements MessageListener
+{
+ public void onMessage(Message message)...
+}
+ 上例中配置了MDB从一个队列中接收消息,它的JNDI绑定名为queue/testQueue。
+ 这个队列必须事先在HornetQ服务器配置文件中配置并部署好的。
+ ResourceAdapter annotation用来指出使用哪个适配器。要使用它必须要引入
+ org.jboss.ejb3.annotation.ResourceAdapter (JBoss AS 5.x或以上)。
+ 这个类在
+ jboss-ejb3-ext-api.jar文件中。该文件可以在JBoss的repository中找到。
+ 另外一个方法是使用部署描述文件(deployment descriptor),即在文件jboss.xml中加入类似以下的内容:
+<message-driven>
+ <ejb-name>ExampleMDB</ejb-name>
+ <resource-adapter-name>hornetq-ra.rar</resource-adapter-name>
+</message-driven>
+你还可以将hornetq-ra.rar改名为jms-ra.rar而不需要任何annotation或额外的部署描述信息。但是你需要
+ 编辑jms-ds.xml文件,将其中的rar-name项改成相应的值。
+
+ HornetQ是JBoss AS 6默认的JMS提供者。从这个版本开始HornetQ的资源适配器名字是
+ jms-ra.rar,并且你不需要在MDB的annotation中指定它。
+
+ HornetQ发布包中的所有例子都使用annotation方法。
+
+ 使用容器管理事务(CMT)
+ 当MDB使用容器管理事务时,消息的传递被包含在一个JTA事务中。事务的提交与回滚是由容器来控制的。如果事务
+ 被回滚,消息传递会进行相应的处理(默认是重新传递消息,如果重新传递次数超过10次,消息就被发往DLQ)。使用
+ annotation配置如下:
+ @MessageDriven(name = "MDB_CMP_TxRequiredExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue")
+ })
+@TransactionManagement(value= TransactionManagementType.CONTAINER)
+@TransactionAttribute(value= TransactionAttributeType.REQUIRED)
+@ResourceAdapter("hornetq-ra.rar")
+public class MDB_CMP_TxRequiredExample implements MessageListener
+{
+ public void onMessage(Message message)...
+}
+ TransactionManagement 表示这个MDB使用容器管理持久性。
+ TransactionAttribute 表示这个MDB要求JTA事务。注意这个annotation的
+ 另外唯一的合法值是TransactionAttributeType.NOT_SUPPORTED,它表示
+ MDB不需要JTA事务支持。
+ 如果要回滚事务,可以调用MessageDrivenContext的
+ setRollbackOnly方法。如下面的代码所示:
+ @Resource
+ MessageDrivenContextContext ctx;
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ //something here fails
+ }
+ catch (Exception e)
+ {
+ ctx.setRollbackOnly();
+ }
+ }
+ 如果你不需要使用XA事务,你可以用一相本地的事务来代替(比如你只有一个JMS资源)。
+ 如下所示:
+ @MessageDriven(name = "MDB_CMP_TxLocalExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "useLocalTx", propertyValue = "true")
+ })
+@TransactionManagement(value = TransactionManagementType.CONTAINER)
+@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
+@ResourceAdapter("hornetq-ra.rar")
+public class MDB_CMP_TxLocalExample implements MessageListener
+{
+ public void onMessage(Message message)...
+}
+
+
+ 使用Bean管理事务(BMT)
+ 消息Bean可以通过配置使用Bean管理的事务(BMT)。在种情况下会创建一个用户事务
+ (User Transaction)。如下所示:
+ @MessageDriven(name = "MDB_BMPExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Dups-ok-acknowledge")
+ })
+@TransactionManagement(value= TransactionManagementType.BEAN)
+@ResourceAdapter("hornetq-ra.rar")
+public class MDB_BMPExample implements MessageListener
+{
+ public void onMessage(Message message)
+}
+ 使用BMT时,消息的传递在用户事务的范围之外,它的通知模式由acknowledgeMode参数决定。
+ 该参数有两个合法的值,即Auto-acknowledge和Dups-ok-acknowledge。请注意,由于消息的传递在事务之外,在MDB中如果发生错误消息
+ 是不会重新传递的。
+ 用户可以像如下所示控制事务的生命周期:
+ @Resource
+ MessageDrivenContext ctx;
+
+ public void onMessage(Message message)
+ {
+ UserTransaction tx;
+ try
+ {
+ TextMessage textMessage = (TextMessage)message;
+
+ String text = textMessage.getText();
+
+ UserTransaction tx = ctx.getUserTransaction();
+
+ tx.begin();
+
+ //do some stuff within the transaction
+
+ tx.commit();
+
+ }
+ catch (Exception e)
+ {
+ tx.rollback();
+ }
+ }
+
+
+ 在MDB中使用选择器
+ MDB可以配置消息选择器。如下所示:
+ @MessageDriven(name = "MDBMessageSelectorExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "color = 'RED'")
+ })
+@TransactionManagement(value= TransactionManagementType.CONTAINER)
+@TransactionAttribute(value= TransactionAttributeType.REQUIRED)
+@ResourceAdapter("hornetq-ra.rar")
+public class MDBMessageSelectorExample implements MessageListener
+{
+ public void onMessage(Message message)....
+}
+
+
+
+ 在JEE模块内发送消息
+ JCA适配器支持发送消息。连接工厂的默认配置在jms-ds.xml文件中,对应的JNDI名字是
+ java:/JmsXA。在JEE中使用它发送消息将作为JTA事务的一部分来对待。
+ 如果消息发送失败,整个事务将回滚,消息会被重新发送。下面是一个MDB发送消息的例子:
+ @MessageDriven(name = "MDBMessageSendTxExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue")
+ })
+@TransactionManagement(value= TransactionManagementType.CONTAINER)
+@TransactionAttribute(value= TransactionAttributeType.REQUIRED)
+@ResourceAdapter("hornetq-ra.rar")
+public class MDBMessageSendTxExample implements MessageListener
+{
+ @Resource(mappedName = "java:/JmsXA")
+ ConnectionFactory connectionFactory;
+
+ @Resource(mappedName = "queue/replyQueue")
+ Queue replyQueue;
+
+ public void onMessage(Message message)
+ {
+ Connection conn = null;
+ try
+ {
+ //Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ //Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text);
+
+ conn = connectionFactory.createConnection();
+
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer producer = sess.createProducer(replyQueue);
+
+ producer.send(sess.createTextMessage("this is a reply"));
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (JMSException e)
+ {
+ }
+ }
+ }
+ }
+ }
+ 在JBoss应用服务器的EJB(包括会话Bean, 实体Bean和消息Bean)、Servlet(包括jsp)我定制的MBean中
+ 都可以使用JMS的JCA适配器来发送消息。
+
+
+ MDB与接收池的大小
+ 包括JBoss在内的绝大多数应用服务器允许用户定义一个池中的MDB数量。在JBoss中这个参数名是MaxPoolSize,它在文件
+ ejb3-interceptors-aop.xml中配置。这个参数不影响实际创建的会话/接收者的数量。资源适配器不知道MDB的具体实现。所以即使你设置MDB池在大小
+ 为1,仍然会有15个会话/接收者被创建(默认值)。如果你想改变会话/接收者创建的数量,你可以通过设置资源适配器的参数
+ maxSession实现。也可以通过设置MDB的激活配置参数来完成:
+ @MessageDriven(name = "MDBMessageSendTxExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")
+ })
+@TransactionManagement(value= TransactionManagementType.CONTAINER)
+@TransactionAttribute(value= TransactionAttributeType.REQUIRED)
+@ResourceAdapter("hornetq-ra.rar")
+public class MyMDB implements MessageListener
+{ ....}
+
+
+
+ 配置JCA适配器
+ 通过JCA适配器可以将HornetQ集成到JEE兼容的模块中,如MDB和EJB。它的配置决定了这些模块如何接收和发送消息。
+ HornetQ的JCA适配器是通过jms-ra.rar部署的。它的配置文件中其中的
+ META-INF/ra.xml。
+ 下面是它的具体配置内容:
+ <resourceadapter>
+ <resourceadapter-class>org.hornetq.ra.HornetQResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>The transport type</description>
+ <config-property-name>ConnectorClassName</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>org.hornetq.core.remoting.impl.invm.InVMConnectorF
+ actory</config-property-value>
+ </config-property>
+ <config-property>
+ <description>The transport configuration. These values must be in the form of key=val;key=val;</description>
+ <config-property-name>ConnectionParameters</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>server-id=0</config-property-value>
+ </config-property>
+
+ <outbound-resourceadapter>
+ <connection-definition>
+ <managedconnectionfactory-class>org.hornetq.ra.HornetQRAManagedConnection
+ Factory</managedconnectionfactory-class>
+
+ <config-property>
+ <description>The default session type</description>
+ <config-property-name>SessionDefaultType</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>javax.jms.Queue</config-property-value>
+ </config-property>
+ <config-property>
+ <description>Try to obtain a lock within specified number of seconds; less
+ than or equal to 0 disable this functionality</description>
+ <config-property-name>UseTryLock</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>0</config-property-value>
+ </config-property>
+
+ <connectionfactory-interface>org.hornetq.ra.HornetQRAConnectionFactory
+ </connectionfactory-interface>
+ <connectionfactororg.hornetq.ra.HornetQConnectionFactoryImplonFactoryImpl
+ </connectionfactory-impl-class>
+ <connection-interface>javax.jms.Session</connection-interface>
+ <connection-impl-class>org.hornetq.ra.HornetQRASession
+ </connection-impl-class>
+ </connection-definition>
+ <transaction-support>XATransaction</transaction-support>
+ <authentication-mechanism>
+ <authentication-mechanism-type>BasicPassword
+ </authentication-mechanism-type>
+ <credential-interface>javax.resource.spi.security.PasswordCredential
+ </credential-interface>
+ </authentication-mechanism>
+ <reauthentication-support>false</reauthentication-support>
+ </outbound-resourceadapter>
+
+ <inbound-resourceadapter>
+ <messageadapter>
+ <messagelistener>
+ <messagelistener-type>javax.jms.MessageListener</messagelistener-type>
+ <activationspec>
+ <activationspec-class>org.hornetq.ra.inflow.HornetQActivationSpec
+ </activationspec-class>
+ <required-config-property>
+ <config-property-name>destination</config-property-name>
+ </required-config-property>
+ </activationspec>
+ </messagelistener>
+ </messageadapter>
+ </inbound-resourceadapter>
+
+ </resourceadapter>
+ 整个配置可以分为三个主要部分
+
+
+ 适配器的全局参数
+
+
+ 适配器外部(outbound)配置。用于在JEE环境中创建JMS资源。
+
+
+ 适配器内部(inbound)配置。用于控制MDB的消息接收。
+
+
+
+ 适配器的全局参数
+ 首先看到的第一个参数是resourceadapter-class。这是HornetQ
+ 的适配器类。此参数不可更改。
+ 在此之后是可配置的参数。前两个配置适配器所使用的传输。其余的用来配置连接工厂。
+ 所有连接工厂的参数在没有定义时使用默认值。参数reconnectAttempts
+ 的默认值取-1,表示如果连接失败,HornetQ会不停地尝试重新连接。这个参数只适用于创建远程
+ 连接的情况。如果是InVm连接器,则永远不可能发生连接故障。
+ 下面给出了每个参数的说明:
+
This example shows how to setup and run HornetQ embedded with remote clients connecting.
+
HornetQ was designed to use POJOs (Plain Old Java Objects), what makes embedding HornetQ as simple as instantiating a few objects.
+
+
HornetQ Embedded could be used from very simple use cases with only InVM support to very complex cases with clustering, persistence and fail over.
+
+
+
Example step-by-step
+
To run the example, simply type mvn -Pserver from this directory to start the server and mvn -Pclient to run the client example
+
In this we don't use any configuration files. (Everything is embedded). We simply instantiate ConfigurationImpl, HornetQServer, start it and operate on JMS regularly
+
+
+
On EmbeddedServer: Create the Configuration, and set the properties accordingly
+
+
+
\ No newline at end of file
diff --git a/examples/core/embedded-remote/src/main/java/org/hornetq/core/example/EmbeddedRemoteExample.java b/examples/core/embedded-remote/src/main/java/org/hornetq/core/example/EmbeddedRemoteExample.java
new file mode 100644
index 0000000000..95a5a6e36a
--- /dev/null
+++ b/examples/core/embedded-remote/src/main/java/org/hornetq/core/example/EmbeddedRemoteExample.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClientConsumer;
+import org.hornetq.api.core.client.ClientMessage;
+import org.hornetq.api.core.client.ClientProducer;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.HornetQClient;
+import org.hornetq.api.core.client.ServerLocator;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+
+/**
+ *
+ * This example shows how to run a HornetQ core client and server embedded in your
+ * own application
+ *
+ * @author Tim Fox
+ *
+ */
+public class EmbeddedRemoteExample
+{
+
+ public static void main(final String[] args)
+ {
+ try
+ {
+ // Step 3. As we are not using a JNDI environment we instantiate the objects directly
+
+ /**
+ * this map with configuration values is not necessary (it configures the default values).
+ * If you modify it to run the example in two different hosts, remember to also modify the
+ * server's Acceptor at {@link EmbeddedServer}
+ */
+ Map map = new HashMap();
+ map.put("host", "localhost");
+ map.put("port", 5445);
+ // -------------------------------------------------------
+
+ ServerLocator serverLocator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName(), map));
+ ClientSessionFactory sf = serverLocator.createSessionFactory();
+
+ // Step 4. Create a core queue
+ ClientSession coreSession = sf.createSession(false, false, false);
+
+ final String queueName = "queue.exampleQueue";
+
+ coreSession.createQueue(queueName, queueName, true);
+
+ coreSession.close();
+
+ ClientSession session = null;
+
+ try
+ {
+
+ // Step 5. Create the session, and producer
+ session = sf.createSession();
+
+ ClientProducer producer = session.createProducer(queueName);
+
+ // Step 6. Create and send a message
+ ClientMessage message = session.createMessage(false);
+
+ final String propName = "myprop";
+
+ message.putStringProperty(propName, "Hello sent at " + new Date());
+
+ System.out.println("Sending the message.");
+
+ producer.send(message);
+
+ // Step 7. Create the message consumer and start the connection
+ ClientConsumer messageConsumer = session.createConsumer(queueName);
+ session.start();
+
+ // Step 8. Receive the message.
+ ClientMessage messageReceived = messageConsumer.receive(1000);
+ System.out.println("Received TextMessage:" + messageReceived.getStringProperty(propName));
+ }
+ finally
+ {
+ // Step 9. Be sure to close our resources!
+ if (sf != null)
+ {
+ sf.close();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/core/embedded-remote/src/main/java/org/hornetq/core/example/EmbeddedServer.java b/examples/core/embedded-remote/src/main/java/org/hornetq/core/example/EmbeddedServer.java
new file mode 100644
index 0000000000..baaf9177a1
--- /dev/null
+++ b/examples/core/embedded-remote/src/main/java/org/hornetq/core/example/EmbeddedServer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.core.config.Configuration;
+import org.hornetq.core.config.impl.ConfigurationImpl;
+import org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory;
+import org.hornetq.core.server.HornetQServer;
+import org.hornetq.core.server.HornetQServers;
+
+/**
+ * An EmbeddedServer
+ * @author Clebert Suconic
+ */
+public class EmbeddedServer
+{
+
+ public static void main(final String arg[]) throws Exception
+ {
+ try
+ {
+ // Step 1. Create the Configuration, and set the properties accordingly
+ Configuration configuration = new ConfigurationImpl();
+ //we only need this for the server lock file
+ configuration.setJournalDirectory("target/data/journal");
+ configuration.setPersistenceEnabled(false);
+ configuration.setSecurityEnabled(false);
+ /**
+ * this map with configuration values is not necessary (it configures the default values).
+ * If you want to modify it to run the example in two different hosts, remember to also
+ * modify the client's Connector at {@link EmbeddedRemoteExample}.
+ */
+ Map map = new HashMap();
+ map.put("host", "localhost");
+ map.put("port", 5445);
+
+ TransportConfiguration transpConf = new TransportConfiguration(NettyAcceptorFactory.class.getName(),map);
+
+ HashSet setTransp = new HashSet();
+ setTransp.add(transpConf);
+
+ configuration.setAcceptorConfigurations(setTransp);
+
+ // Step 2. Create and start the server
+ HornetQServer server = HornetQServers.newHornetQServer(configuration);
+ server.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+}
diff --git a/examples/core/embedded/pom.xml b/examples/core/embedded/pom.xml
new file mode 100644
index 0000000000..d6b92b4cc5
--- /dev/null
+++ b/examples/core/embedded/pom.xml
@@ -0,0 +1,78 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.core
+ core-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-core-embedded-example
+ jar
+ HornetQ Core Embedded Example
+
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-commons
+ ${project.version}
+
+
+ io.netty
+ netty-all
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnp-client
+ 5.0.5.Final
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+ example
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.1
+
+
+ package
+
+ java
+
+
+
+
+ org.hornetq.core.example.EmbeddedExample
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/embedded/readme.html b/examples/core/embedded/readme.html
new file mode 100644
index 0000000000..ac41734bc0
--- /dev/null
+++ b/examples/core/embedded/readme.html
@@ -0,0 +1,97 @@
+
+
+ HornetQ Embedded Example
+
+
+
+
+
+
Embedded Example
+
+
This example shows how to setup and run HornetQ embedded.
+
HornetQ was designed to use POJOs (Plain Old Java Objects), what makes embedding HornetQ as simple as instantiating a few objects.
+
In this example, we are using two jars:
+
+
hornetq-server.jar
+
netty.jar
+
+
+
HornetQ Embedded could be used from very simple use cases with only InVM support to very complex cases with clustering, persistence and fail over.
+
+
Example step-by-step
+
To run the example, simply type mvn -Pexample from this directory
+
In this we don't use any configuration files. (Everything is embedded). We simply instantiate ConfigurationImpl, HornetQServer, start it and operate on JMS regularly
+
+
+
Create the Configuration, and set the properties accordingly
+
+
+
\ No newline at end of file
diff --git a/examples/core/embedded/src/main/java/org/hornetq/core/example/EmbeddedExample.java b/examples/core/embedded/src/main/java/org/hornetq/core/example/EmbeddedExample.java
new file mode 100644
index 0000000000..96e3b0275d
--- /dev/null
+++ b/examples/core/embedded/src/main/java/org/hornetq/core/example/EmbeddedExample.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.Date;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClientConsumer;
+import org.hornetq.api.core.client.ClientMessage;
+import org.hornetq.api.core.client.ClientProducer;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.HornetQClient;
+import org.hornetq.api.core.client.ServerLocator;
+import org.hornetq.core.config.Configuration;
+import org.hornetq.core.config.impl.ConfigurationImpl;
+import org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory;
+import org.hornetq.core.remoting.impl.invm.InVMConnectorFactory;
+import org.hornetq.core.server.HornetQServer;
+import org.hornetq.core.server.HornetQServers;
+
+/**
+ *
+ * This example shows how to run a HornetQ core client and server embedded in your
+ * own application
+ *
+ * @author Tim Fox
+ *
+ */
+public class EmbeddedExample
+{
+
+ public static void main(final String[] args) throws Exception
+ {
+ try
+ {
+ // Step 1. Create the Configuration, and set the properties accordingly
+ Configuration configuration = new ConfigurationImpl();
+ //we only need this for the server lock file
+ configuration.setJournalDirectory("target/data/journal");
+ configuration.setPersistenceEnabled(false);
+ configuration.setSecurityEnabled(false);
+ configuration.getAcceptorConfigurations().add(new TransportConfiguration(InVMAcceptorFactory.class.getName()));
+
+ // Step 2. Create and start the server
+ HornetQServer server = HornetQServers.newHornetQServer(configuration);
+ server.start();
+
+ // Step 3. As we are not using a JNDI environment we instantiate the objects directly
+ ServerLocator serverLocator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(InVMConnectorFactory.class.getName()));
+ ClientSessionFactory sf = serverLocator.createSessionFactory();
+
+ // Step 4. Create a core queue
+ ClientSession coreSession = sf.createSession(false, false, false);
+
+ final String queueName = "queue.exampleQueue";
+
+ coreSession.createQueue(queueName, queueName, true);
+
+ coreSession.close();
+
+ ClientSession session = null;
+
+ try
+ {
+
+ // Step 5. Create the session, and producer
+ session = sf.createSession();
+
+ ClientProducer producer = session.createProducer(queueName);
+
+ // Step 6. Create and send a message
+ ClientMessage message = session.createMessage(false);
+
+ final String propName = "myprop";
+
+ message.putStringProperty(propName, "Hello sent at " + new Date());
+
+ System.out.println("Sending the message.");
+
+ producer.send(message);
+
+ // Step 7. Create the message consumer and start the connection
+ ClientConsumer messageConsumer = session.createConsumer(queueName);
+ session.start();
+
+ // Step 8. Receive the message.
+ ClientMessage messageReceived = messageConsumer.receive(1000);
+ System.out.println("Received TextMessage:" + messageReceived.getStringProperty(propName));
+ }
+ finally
+ {
+ // Step 9. Be sure to close our resources!
+ if (sf != null)
+ {
+ sf.close();
+ }
+
+ // Step 10. Stop the server
+ server.stop();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+}
diff --git a/examples/core/microcontainer/pom.xml b/examples/core/microcontainer/pom.xml
new file mode 100644
index 0000000000..f3d92f55b9
--- /dev/null
+++ b/examples/core/microcontainer/pom.xml
@@ -0,0 +1,84 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.core
+ core-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-core-microcontainer-example
+ jar
+ HornetQ Core Microcontainer Example
+
+
+
+ org.hornetq
+ hornetq-bootstrap
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-commons
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnp-client
+ 5.0.5.Final
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+ example
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.1
+
+
+ package
+
+ java
+
+
+
+
+ org.hornetq.core.example.EmbeddedMicroContainerExample
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/microcontainer/readme.html b/examples/core/microcontainer/readme.html
new file mode 100644
index 0000000000..40d2832997
--- /dev/null
+++ b/examples/core/microcontainer/readme.html
@@ -0,0 +1,82 @@
+
+
+ HornetQ Embedded Example
+
+
+
+
+
+
Micro Container Example
+
+
This examples shows how to setup and run HornetQ through the Micro Container.
+
Refer to the user's manual for the list of required Jars, since JBoss Micro Container requires a few jars.
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
In this we don't use any configuration files. (Everything is embedded). We simply instantiate ConfigurationImpl, HornetQServer, start it and operate on JMS regularly
+
+
+
+
Start the server
+
+ hornetq = new HornetQBootstrapServer("./server0/hornetq-beans.xml");
+ hornetq.run();
+
+
+
As we are not using a JNDI environment we instantiate the objects directly
+
+
+
diff --git a/examples/core/microcontainer/src/main/java/org/hornetq/core/example/EmbeddedMicroContainerExample.java b/examples/core/microcontainer/src/main/java/org/hornetq/core/example/EmbeddedMicroContainerExample.java
new file mode 100644
index 0000000000..ac5ace4d5a
--- /dev/null
+++ b/examples/core/microcontainer/src/main/java/org/hornetq/core/example/EmbeddedMicroContainerExample.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.Date;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.*;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.integration.bootstrap.HornetQBootstrapServer;
+
+/**
+ *
+ * This example shows how to run a HornetQ core client and server embedded in your
+ * own application
+ *
+ * @author Tim Fox
+ *
+ */
+public class EmbeddedMicroContainerExample
+{
+
+ public static void main(final String[] args) throws Exception
+ {
+
+ HornetQBootstrapServer hornetQ = null;
+ try
+ {
+
+ // Step 1. Start the server
+ hornetQ = new HornetQBootstrapServer("hornetq-beans.xml");
+ hornetQ.run();
+
+ // Step 2. As we are not using a JNDI environment we instantiate the objects directly
+ ServerLocator serverLocator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName()));
+ ClientSessionFactory sf = serverLocator.createSessionFactory();
+
+ // Step 3. Create a core queue
+ ClientSession coreSession = sf.createSession(false, false, false);
+
+ final String queueName = "queue.exampleQueue";
+
+ coreSession.createQueue(queueName, queueName, true);
+
+ coreSession.close();
+
+ ClientSession session = null;
+
+ try
+ {
+
+ // Step 4. Create the session, and producer
+ session = sf.createSession();
+
+ ClientProducer producer = session.createProducer(queueName);
+
+ // Step 5. Create and send a message
+ ClientMessage message = session.createMessage(false);
+
+ final String propName = "myprop";
+
+ message.putStringProperty(propName, "Hello sent at " + new Date());
+
+ System.out.println("Sending the message.");
+
+ producer.send(message);
+
+ // Step 6. Create the message consumer and start the connection
+ ClientConsumer messageConsumer = session.createConsumer(queueName);
+ session.start();
+
+ // Step 7. Receive the message.
+ ClientMessage messageReceived = messageConsumer.receive(1000);
+
+ System.out.println("Received TextMessage:" + messageReceived.getStringProperty(propName));
+ }
+ finally
+ {
+ // Step 8. Be sure to close our resources!
+ if (sf != null)
+ {
+ sf.close();
+ }
+
+ // Step 9. Shutdown the container
+ if (hornetQ != null)
+ {
+ hornetQ.shutDown();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+}
diff --git a/examples/core/microcontainer/src/main/resources/hornetq-beans.xml b/examples/core/microcontainer/src/main/resources/hornetq-beans.xml
new file mode 100644
index 0000000000..b68c7ae8cb
--- /dev/null
+++ b/examples/core/microcontainer/src/main/resources/hornetq-beans.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/core/microcontainer/src/main/resources/hornetq-configuration.xml b/examples/core/microcontainer/src/main/resources/hornetq-configuration.xml
new file mode 100644
index 0000000000..766b4b1819
--- /dev/null
+++ b/examples/core/microcontainer/src/main/resources/hornetq-configuration.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ target/data/messaging/bindings
+
+ target/data/messaging/journal
+
+ target/data/messaging/largemessages
+
+ target/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ false
+
+ false
+
+
diff --git a/examples/core/perf/perf.properties b/examples/core/perf/perf.properties
new file mode 100644
index 0000000000..7e8b3d5a9f
--- /dev/null
+++ b/examples/core/perf/perf.properties
@@ -0,0 +1,21 @@
+num-messages=100000
+num-warmup-messages=1000
+message-size=1024
+durable=false
+transacted=false
+batch-size=1048576
+drain-queue=false
+throttle-rate=-1
+address=perfAddress
+queue-name=perfQueue
+host=localhost
+port=5445
+tcp-buffer=2048576
+tcp-no-delay=false
+confirmation-window=1048576
+producer-window=1048576
+consumer-window=1048576
+pre-ack=false
+block-ack=false
+block-persistent=false
+use-send-acks=true
diff --git a/examples/core/perf/pom.xml b/examples/core/perf/pom.xml
new file mode 100644
index 0000000000..759a9bcb50
--- /dev/null
+++ b/examples/core/perf/pom.xml
@@ -0,0 +1,180 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.core
+ core-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-core-perf-example
+ jar
+ HornetQ Perf Example
+
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-commons
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnp-client
+ 5.0.5.Final
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+ default
+
+ true
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+ true
+ ${basedir}/target/classes/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+ false
+ ${basedir}/target/classes/server0
+
+
+
+ org.hornetq.examples.core
+ hornetq-core-perf-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+
+
+
+
+ listener
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.1
+
+
+ package
+
+ java
+
+
+
+
+ org.hornetq.core.example.PerfListener
+
+
+
+
+
+
+ sender
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.1
+
+
+ package
+
+ java
+
+
+
+
+ org.hornetq.core.example.PerfSender
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/perf/src/main/java/org/hornetq/core/example/PerfBase.java b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfBase.java
new file mode 100644
index 0000000000..d837a7ead7
--- /dev/null
+++ b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfBase.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Logger;
+
+import org.hornetq.api.core.Message;
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClientConsumer;
+import org.hornetq.api.core.client.ClientMessage;
+import org.hornetq.api.core.client.ClientProducer;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.HornetQClient;
+import org.hornetq.api.core.client.MessageHandler;
+import org.hornetq.api.core.client.SendAcknowledgementHandler;
+import org.hornetq.api.core.client.ServerLocator;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.core.remoting.impl.netty.TransportConstants;
+import org.hornetq.utils.TokenBucketLimiter;
+import org.hornetq.utils.TokenBucketLimiterImpl;
+
+/**
+ *
+ * A PerfBase
+ *
+ * @author Tim Fox
+ *
+ *
+ */
+public abstract class PerfBase
+{
+ private static final Logger log = Logger.getLogger(PerfSender.class.getName());
+
+ private static final String DEFAULT_PERF_PROPERTIES_FILE_NAME = "perf.properties";
+
+ private static byte[] randomByteArray(final int length)
+ {
+ byte[] bytes = new byte[length];
+
+ Random random = new Random();
+
+ for (int i = 0; i < length; i++)
+ {
+ bytes[i] = Integer.valueOf(random.nextInt()).byteValue();
+ }
+
+ return bytes;
+ }
+
+ protected static String getPerfFileName(final String[] args)
+ {
+ String fileName;
+
+ if (args.length > 0)
+ {
+ fileName = args[0];
+ }
+ else
+ {
+ fileName = PerfBase.DEFAULT_PERF_PROPERTIES_FILE_NAME;
+ }
+
+ PerfBase.log.info("Using file name " + fileName);
+
+ return fileName;
+ }
+
+ protected static PerfParams getParams(final String fileName) throws Exception
+ {
+ Properties props = null;
+
+ InputStream is = null;
+
+ try
+ {
+ is = new FileInputStream(fileName);
+
+ props = new Properties();
+
+ props.load(is);
+ }
+ finally
+ {
+ if (is != null)
+ {
+ is.close();
+ }
+ }
+
+ int noOfMessages = Integer.valueOf(props.getProperty("num-messages"));
+ int noOfWarmupMessages = Integer.valueOf(props.getProperty("num-warmup-messages"));
+ int messageSize = Integer.valueOf(props.getProperty("message-size"));
+ boolean durable = Boolean.valueOf(props.getProperty("durable"));
+ boolean transacted = Boolean.valueOf(props.getProperty("transacted"));
+ int batchSize = Integer.valueOf(props.getProperty("batch-size"));
+ boolean drainQueue = Boolean.valueOf(props.getProperty("drain-queue"));
+ String queueName = props.getProperty("queue-name");
+ String address = props.getProperty("address");
+ int throttleRate = Integer.valueOf(props.getProperty("throttle-rate"));
+ String host = props.getProperty("host");
+ int port = Integer.valueOf(props.getProperty("port"));
+ int tcpBufferSize = Integer.valueOf(props.getProperty("tcp-buffer"));
+ boolean tcpNoDelay = Boolean.valueOf(props.getProperty("tcp-no-delay"));
+ boolean preAck = Boolean.valueOf(props.getProperty("pre-ack"));
+ int confirmationWindowSize = Integer.valueOf(props.getProperty("confirmation-window"));
+ int producerWindowSize = Integer.valueOf(props.getProperty("producer-window"));
+ int consumerWindowSize = Integer.valueOf(props.getProperty("consumer-window"));
+ boolean blockOnACK = Boolean.valueOf(props.getProperty("block-ack", "false"));
+ boolean blockOnPersistent = Boolean.valueOf(props.getProperty("block-persistent", "false"));
+ boolean useSendAcks = Boolean.valueOf(props.getProperty("use-send-acks", "false"));
+
+ PerfBase.log.info("num-messages: " + noOfMessages);
+ PerfBase.log.info("num-warmup-messages: " + noOfWarmupMessages);
+ PerfBase.log.info("message-size: " + messageSize);
+ PerfBase.log.info("durable: " + durable);
+ PerfBase.log.info("transacted: " + transacted);
+ PerfBase.log.info("batch-size: " + batchSize);
+ PerfBase.log.info("drain-queue: " + drainQueue);
+ PerfBase.log.info("address: " + address);
+ PerfBase.log.info("queue name: " + queueName);
+ PerfBase.log.info("throttle-rate: " + throttleRate);
+ PerfBase.log.info("host:" + host);
+ PerfBase.log.info("port: " + port);
+ PerfBase.log.info("tcp buffer: " + tcpBufferSize);
+ PerfBase.log.info("tcp no delay: " + tcpNoDelay);
+ PerfBase.log.info("pre-ack: " + preAck);
+ PerfBase.log.info("confirmation-window: " + confirmationWindowSize);
+ PerfBase.log.info("producer-window: " + producerWindowSize);
+ PerfBase.log.info("consumer-window: " + consumerWindowSize);
+ PerfBase.log.info("block-ack:" + blockOnACK);
+ PerfBase.log.info("block-persistent:" + blockOnPersistent);
+ PerfBase.log.info("use-send-acks:" + useSendAcks);
+
+ if (useSendAcks && confirmationWindowSize < 1)
+ {
+ throw new IllegalArgumentException("If you use send acks, then need to set confirmation-window-size to a positive integer");
+ }
+
+ PerfParams perfParams = new PerfParams();
+ perfParams.setNoOfMessagesToSend(noOfMessages);
+ perfParams.setNoOfWarmupMessages(noOfWarmupMessages);
+ perfParams.setMessageSize(messageSize);
+ perfParams.setDurable(durable);
+ perfParams.setSessionTransacted(transacted);
+ perfParams.setBatchSize(batchSize);
+ perfParams.setDrainQueue(drainQueue);
+ perfParams.setQueueName(queueName);
+ perfParams.setAddress(address);
+ perfParams.setThrottleRate(throttleRate);
+ perfParams.setHost(host);
+ perfParams.setPort(port);
+ perfParams.setTcpBufferSize(tcpBufferSize);
+ perfParams.setTcpNoDelay(tcpNoDelay);
+ perfParams.setPreAck(preAck);
+ perfParams.setConfirmationWindow(confirmationWindowSize);
+ perfParams.setProducerWindow(producerWindowSize);
+ perfParams.setConsumerWindow(consumerWindowSize);
+ perfParams.setBlockOnACK(blockOnACK);
+ perfParams.setBlockOnPersistent(blockOnPersistent);
+ perfParams.setUseSendAcks(useSendAcks);
+
+ return perfParams;
+ }
+
+ private final PerfParams perfParams;
+
+ protected PerfBase(final PerfParams perfParams)
+ {
+ this.perfParams = perfParams;
+ }
+
+ private ClientSessionFactory factory;
+
+ private long start;
+
+ private void init(final boolean transacted, final String queueName) throws Exception
+ {
+ Map params = new HashMap();
+
+ params.put(TransportConstants.TCP_NODELAY_PROPNAME, perfParams.isTcpNoDelay());
+ params.put(TransportConstants.TCP_SENDBUFFER_SIZE_PROPNAME, perfParams.getTcpBufferSize());
+ params.put(TransportConstants.TCP_RECEIVEBUFFER_SIZE_PROPNAME, perfParams.getTcpBufferSize());
+
+ params.put(TransportConstants.HOST_PROP_NAME, perfParams.getHost());
+ params.put(TransportConstants.PORT_PROP_NAME, perfParams.getPort());
+
+ ServerLocator serverLocator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName(), params));
+ serverLocator.setPreAcknowledge(perfParams.isPreAck());
+ serverLocator.setConfirmationWindowSize(perfParams.getConfirmationWindow());
+ serverLocator.setProducerWindowSize(perfParams.getProducerWindow());
+ serverLocator.setConsumerWindowSize(perfParams.getConsumerWindow());
+ serverLocator.setAckBatchSize(perfParams.getBatchSize());
+
+ serverLocator.setBlockOnAcknowledge(perfParams.isBlockOnACK());
+ serverLocator.setBlockOnDurableSend(perfParams.isBlockOnPersistent());
+ factory = serverLocator.createSessionFactory();
+
+ }
+
+ private void displayAverage(final long numberOfMessages, final long start, final long end)
+ {
+ double duration = (1.0 * end - start) / 1000; // in seconds
+ double average = 1.0 * numberOfMessages / duration;
+ PerfBase.log.info(String.format("average: %.2f msg/s (%d messages in %2.2fs)",
+ average,
+ numberOfMessages,
+ duration));
+ }
+
+ protected void runSender()
+ {
+ try
+ {
+ PerfBase.log.info("params = " + perfParams);
+
+ init(perfParams.isSessionTransacted(), perfParams.getQueueName());
+
+ if (perfParams.isDrainQueue())
+ {
+ drainQueue();
+ }
+
+ start = System.currentTimeMillis();
+ PerfBase.log.info("warming up by sending " + perfParams.getNoOfWarmupMessages() + " messages");
+ sendMessages(perfParams.getNoOfWarmupMessages(),
+ perfParams.getBatchSize(),
+ perfParams.isDurable(),
+ perfParams.isSessionTransacted(),
+ false,
+ perfParams.getThrottleRate(),
+ perfParams.getMessageSize(),
+ perfParams.isUseSendAcks());
+ PerfBase.log.info("warmed up");
+ start = System.currentTimeMillis();
+ sendMessages(perfParams.getNoOfMessagesToSend(),
+ perfParams.getBatchSize(),
+ perfParams.isDurable(),
+ perfParams.isSessionTransacted(),
+ true,
+ perfParams.getThrottleRate(),
+ perfParams.getMessageSize(),
+ perfParams.isUseSendAcks());
+ long end = System.currentTimeMillis();
+ displayAverage(perfParams.getNoOfMessagesToSend(), start, end);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ protected void runListener()
+ {
+ ClientSession session = null;
+
+ try
+ {
+ init(perfParams.isSessionTransacted(), perfParams.getQueueName());
+
+ session = factory.createSession(!perfParams.isSessionTransacted(), !perfParams.isSessionTransacted());
+
+ if (perfParams.isDrainQueue())
+ {
+ drainQueue();
+ }
+
+ ClientConsumer consumer = session.createConsumer(perfParams.getQueueName());
+
+ session.start();
+
+ PerfBase.log.info("READY!!!");
+
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ consumer.setMessageHandler(new PerfListener(session, countDownLatch, perfParams));
+ countDownLatch.await();
+ long end = System.currentTimeMillis();
+ // start was set on the first received message
+ displayAverage(perfParams.getNoOfMessagesToSend(), start, end);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ if (factory != null)
+ {
+ try
+ {
+ factory.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private void drainQueue() throws Exception
+ {
+ PerfBase.log.info("Draining queue");
+
+ ClientSession session = null;
+
+ try
+ {
+ session = factory.createSession();
+
+ ClientConsumer consumer = session.createConsumer(perfParams.getQueueName());
+
+ session.start();
+
+ ClientMessage message = null;
+
+ int count = 0;
+ do
+ {
+ message = consumer.receive(3000);
+
+ if (message != null)
+ {
+ message.acknowledge();
+
+ count++;
+ }
+ }
+ while (message != null);
+
+ PerfBase.log.info("Drained " + count + " messages");
+ }
+ finally
+ {
+ if (session != null)
+ {
+ session.close();
+ }
+ }
+ }
+
+ private void sendMessages(final int numberOfMessages,
+ final int txBatchSize,
+ final boolean durable,
+ final boolean transacted,
+ final boolean display,
+ final int throttleRate,
+ final int messageSize,
+ final boolean useSendAcks) throws Exception
+ {
+ ClientSession session = null;
+
+ try
+ {
+ session = factory.createSession(!transacted, !transacted);
+
+ CountDownLatch theLatch = null;
+
+ if (useSendAcks)
+ {
+ final CountDownLatch latch = new CountDownLatch(numberOfMessages);
+
+ class MySendAckHandler implements SendAcknowledgementHandler
+ {
+ public void sendAcknowledged(Message message)
+ {
+ latch.countDown();
+ }
+ }
+
+ session.setSendAcknowledgementHandler(new MySendAckHandler());
+
+ theLatch = latch;
+ }
+
+ ClientProducer producer = session.createProducer(perfParams.getAddress());
+
+ ClientMessage message = session.createMessage(durable);
+
+ byte[] payload = PerfBase.randomByteArray(messageSize);
+
+ message.getBodyBuffer().writeBytes(payload);
+
+ final int modulo = 2000;
+
+ TokenBucketLimiter tbl = throttleRate != -1 ? new TokenBucketLimiterImpl(throttleRate, false) : null;
+
+ boolean committed = false;
+
+ for (int i = 1; i <= numberOfMessages; i++)
+ {
+ producer.send(message);
+
+ if (transacted)
+ {
+ if (i % txBatchSize == 0)
+ {
+ session.commit();
+ committed = true;
+ }
+ else
+ {
+ committed = false;
+ }
+ }
+ if (display && i % modulo == 0)
+ {
+ double duration = (1.0 * System.currentTimeMillis() - start) / 1000;
+ PerfBase.log.info(String.format("sent %6d messages in %2.2fs", i, duration));
+ }
+
+ // log.info("sent message " + i);
+
+ if (tbl != null)
+ {
+ tbl.limit();
+ }
+ }
+
+ if (transacted && !committed)
+ {
+ session.commit();
+ }
+
+ session.close();
+
+ if (useSendAcks)
+ {
+ theLatch.await();
+ }
+ }
+ finally
+ {
+ if (session != null)
+ {
+ session.close();
+ }
+ }
+ }
+
+ private class PerfListener implements MessageHandler
+ {
+ private final CountDownLatch countDownLatch;
+
+ private final PerfParams perfParams;
+
+ private boolean warmingUp = true;
+
+ private boolean started = false;
+
+ private final int modulo;
+
+ private final AtomicLong count = new AtomicLong(0);
+
+ private final ClientSession session;
+
+ public PerfListener(final ClientSession session, final CountDownLatch countDownLatch, final PerfParams perfParams)
+ {
+ this.session = session;
+ this.countDownLatch = countDownLatch;
+ this.perfParams = perfParams;
+ warmingUp = perfParams.getNoOfWarmupMessages() > 0;
+ modulo = 2000;
+ }
+
+ public void onMessage(final ClientMessage message)
+ {
+ try
+ {
+ if (warmingUp)
+ {
+ boolean committed = checkCommit(session);
+ if (count.incrementAndGet() == perfParams.getNoOfWarmupMessages())
+ {
+ PerfBase.log.info("warmed up after receiving " + count.longValue() + " msgs");
+ if (!committed)
+ {
+ checkCommit(session);
+ }
+ warmingUp = false;
+ }
+ return;
+ }
+
+ if (!started)
+ {
+ started = true;
+ // reset count to take stats
+ count.set(0);
+ start = System.currentTimeMillis();
+ }
+
+ message.acknowledge();
+
+ long currentCount = count.incrementAndGet();
+ boolean committed = checkCommit(session);
+ if (currentCount == perfParams.getNoOfMessagesToSend())
+ {
+ if (!committed)
+ {
+ checkCommit(session);
+ }
+ countDownLatch.countDown();
+ }
+ if (currentCount % modulo == 0)
+ {
+ double duration = (1.0 * System.currentTimeMillis() - start) / 1000;
+ PerfBase.log.info(String.format("received %6d messages in %2.2fs", currentCount, duration));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private boolean checkCommit(final ClientSession session) throws Exception
+ {
+ if (perfParams.isSessionTransacted())
+ {
+ if (count.longValue() % perfParams.getBatchSize() == 0)
+ {
+ session.commit();
+
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/examples/core/perf/src/main/java/org/hornetq/core/example/PerfListener.java b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfListener.java
new file mode 100644
index 0000000000..355aa0cb26
--- /dev/null
+++ b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfListener.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.logging.Logger;
+
+/**
+ *
+ * A PerfListener
+ *
+ * @author Tim Fox
+ *
+ *
+ */
+public class PerfListener extends PerfBase
+{
+ private static final Logger log = Logger.getLogger(PerfListener.class.getName());
+
+ public static void main(final String[] args)
+ {
+ try
+ {
+ String fileName = PerfBase.getPerfFileName(args);
+
+ PerfParams params = PerfBase.getParams(fileName);
+
+ new PerfListener(params).run();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private PerfListener(final PerfParams perfParams)
+ {
+ super(perfParams);
+ }
+
+ public void run() throws Exception
+ {
+ runListener();
+ }
+
+}
diff --git a/examples/core/perf/src/main/java/org/hornetq/core/example/PerfParams.java b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfParams.java
new file mode 100644
index 0000000000..738fe9a26b
--- /dev/null
+++ b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfParams.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.io.Serializable;
+
+/**
+ *
+ * Class that holds the parameters used in the performance examples
+ *
+ * @author Andy Taylor
+ */
+public class PerfParams implements Serializable
+{
+ private static final long serialVersionUID = -4336539641012356002L;
+
+ private int noOfMessagesToSend = 1000;
+
+ private int noOfWarmupMessages;
+
+ private int messageSize = 1024; // in bytes
+
+ private boolean durable = false;
+
+ private boolean isSessionTransacted = false;
+
+ private int batchSize = 5000;
+
+ private boolean drainQueue = true;
+
+ private String queueName;
+
+ private String address;
+
+ private int throttleRate;
+
+ private String host;
+
+ private int port;
+
+ private int tcpBufferSize;
+
+ private boolean tcpNoDelay;
+
+ private boolean preAck;
+
+ private int confirmationWindow = -1;
+
+ private int producerWindow;
+
+ private int consumerWindow;
+
+ private boolean blockOnPersistent = true;
+
+ private boolean blockOnACK = true;
+
+ private boolean useSendAcks;
+
+ public boolean isBlockOnPersistent()
+ {
+ return blockOnPersistent;
+ }
+
+ public void setBlockOnPersistent(final boolean blockOnPersistent)
+ {
+ this.blockOnPersistent = blockOnPersistent;
+ }
+
+ public boolean isBlockOnACK()
+ {
+ return blockOnACK;
+ }
+
+ public void setBlockOnACK(final boolean blockOnACK)
+ {
+ this.blockOnACK = blockOnACK;
+ }
+
+ public int getNoOfMessagesToSend()
+ {
+ return noOfMessagesToSend;
+ }
+
+ public void setNoOfMessagesToSend(final int noOfMessagesToSend)
+ {
+ this.noOfMessagesToSend = noOfMessagesToSend;
+ }
+
+ public int getNoOfWarmupMessages()
+ {
+ return noOfWarmupMessages;
+ }
+
+ public void setNoOfWarmupMessages(final int noOfWarmupMessages)
+ {
+ this.noOfWarmupMessages = noOfWarmupMessages;
+ }
+
+ public int getMessageSize()
+ {
+ return messageSize;
+ }
+
+ public void setMessageSize(final int messageSize)
+ {
+ this.messageSize = messageSize;
+ }
+
+ public boolean isDurable()
+ {
+ return durable;
+ }
+
+ public void setDurable(final boolean durable)
+ {
+ this.durable = durable;
+ }
+
+ public boolean isSessionTransacted()
+ {
+ return isSessionTransacted;
+ }
+
+ public void setSessionTransacted(final boolean sessionTransacted)
+ {
+ isSessionTransacted = sessionTransacted;
+ }
+
+ public int getBatchSize()
+ {
+ return batchSize;
+ }
+
+ public void setBatchSize(final int batchSize)
+ {
+ this.batchSize = batchSize;
+ }
+
+ public boolean isDrainQueue()
+ {
+ return drainQueue;
+ }
+
+ public void setDrainQueue(final boolean drainQueue)
+ {
+ this.drainQueue = drainQueue;
+ }
+
+ public String getQueueName()
+ {
+ return queueName;
+ }
+
+ public void setQueueName(final String queueName)
+ {
+ this.queueName = queueName;
+ }
+
+ public String getAddress()
+ {
+ return address;
+ }
+
+ public void setAddress(final String address)
+ {
+ this.address = address;
+ }
+
+ public int getThrottleRate()
+ {
+ return throttleRate;
+ }
+
+ public void setThrottleRate(final int throttleRate)
+ {
+ this.throttleRate = throttleRate;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "message to send = " + noOfMessagesToSend +
+ ", Durable = " +
+ durable +
+ ", session transacted = " +
+ isSessionTransacted +
+ (isSessionTransacted ? ", transaction batch size = " + batchSize : "") +
+ ", drain queue = " +
+ drainQueue +
+ ", queue name = " +
+ queueName +
+ ", Throttle rate = " +
+ throttleRate +
+ ", blockOnPersistent = " +
+ blockOnPersistent +
+ ". blockOnACK = " +
+ blockOnACK;
+ }
+
+ public synchronized String getHost()
+ {
+ return host;
+ }
+
+ public synchronized void setHost(final String host)
+ {
+ this.host = host;
+ }
+
+ public synchronized int getPort()
+ {
+ return port;
+ }
+
+ public synchronized void setPort(final int port)
+ {
+ this.port = port;
+ }
+
+ public synchronized int getTcpBufferSize()
+ {
+ return tcpBufferSize;
+ }
+
+ public synchronized void setTcpBufferSize(final int tcpBufferSize)
+ {
+ this.tcpBufferSize = tcpBufferSize;
+ }
+
+ public synchronized boolean isTcpNoDelay()
+ {
+ return tcpNoDelay;
+ }
+
+ public synchronized void setTcpNoDelay(final boolean tcpNoDelay)
+ {
+ this.tcpNoDelay = tcpNoDelay;
+ }
+
+ public synchronized boolean isPreAck()
+ {
+ return preAck;
+ }
+
+ public synchronized void setPreAck(final boolean preAck)
+ {
+ this.preAck = preAck;
+ }
+
+ public synchronized int getConfirmationWindow()
+ {
+ return confirmationWindow;
+ }
+
+ public synchronized void setConfirmationWindow(final int confirmationWindow)
+ {
+ this.confirmationWindow = confirmationWindow;
+ }
+
+ public int getProducerWindow()
+ {
+ return producerWindow;
+ }
+
+ public void setProducerWindow(final int producerWindow)
+ {
+ this.producerWindow = producerWindow;
+ }
+
+ public int getConsumerWindow()
+ {
+ return consumerWindow;
+ }
+
+ public void setConsumerWindow(final int consumerWindow)
+ {
+ this.consumerWindow = consumerWindow;
+ }
+
+ public boolean isUseSendAcks()
+ {
+ return useSendAcks;
+ }
+
+ public void setUseSendAcks(boolean useSendAcks)
+ {
+ this.useSendAcks = useSendAcks;
+ }
+}
diff --git a/examples/core/perf/src/main/java/org/hornetq/core/example/PerfSender.java b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfSender.java
new file mode 100644
index 0000000000..9c86a4fc61
--- /dev/null
+++ b/examples/core/perf/src/main/java/org/hornetq/core/example/PerfSender.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.logging.Logger;
+
+/**
+ *
+ * A PerfSender
+ *
+ * @author Tim Fox
+ *
+ *
+ */
+public class PerfSender extends PerfBase
+{
+ private static final Logger log = Logger.getLogger(PerfSender.class.getName());
+
+ public static void main(final String[] args)
+ {
+ try
+ {
+ String fileName = PerfBase.getPerfFileName(args);
+
+ PerfParams params = PerfBase.getParams(fileName);
+
+ new PerfSender(params).run();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private PerfSender(final PerfParams perfParams)
+ {
+ super(perfParams);
+ }
+
+ public void run() throws Exception
+ {
+ runSender();
+ }
+
+}
diff --git a/examples/core/perf/src/main/resources/server0/hornetq-beans.xml b/examples/core/perf/src/main/resources/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..1ab8e95eaa
--- /dev/null
+++ b/examples/core/perf/src/main/resources/server0/hornetq-beans.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/core/perf/src/main/resources/server0/hornetq-configuration-messaging-lab.xml b/examples/core/perf/src/main/resources/server0/hornetq-configuration-messaging-lab.xml
new file mode 100644
index 0000000000..514766e7d1
--- /dev/null
+++ b/examples/core/perf/src/main/resources/server0/hornetq-configuration-messaging-lab.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ false
+
+ true
+
+ /hornetq-data/large-messages
+ /hornetq-data/bindings
+ /hornetq-data/journal
+ /hornetq-data/paging
+
+
+
+ perfAddress
+
+
+
+
diff --git a/examples/core/perf/src/main/resources/server0/hornetq-configuration.xml b/examples/core/perf/src/main/resources/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..3ad5b50c14
--- /dev/null
+++ b/examples/core/perf/src/main/resources/server0/hornetq-configuration.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ target/server0/data/messaging/bindings
+
+ target/server0/data/messaging/journal
+
+ target/server0/data/messaging/largemessages
+
+ target/server0/data/messaging/paging
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ false
+
+ true
+
+ true
+ true
+ ASYNCIO
+ 20
+ 20000
+ false
+ false
+
+
+
+
+
+ perfAddress
+
+
+
+
+
+
diff --git a/examples/core/pom.xml b/examples/core/pom.xml
new file mode 100644
index 0000000000..c70dcd160f
--- /dev/null
+++ b/examples/core/pom.xml
@@ -0,0 +1,20 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples
+ hornetq-examples
+ 2.5.0-SNAPSHOT
+
+
+ org.hornetq.examples.core
+ core-examples
+ pom
+ HornetQ Core Examples
+
+
+ 231.7.7.7
+
+
+
diff --git a/examples/core/twitter-connector/pom.xml b/examples/core/twitter-connector/pom.xml
new file mode 100644
index 0000000000..eb4d3a3b00
--- /dev/null
+++ b/examples/core/twitter-connector/pom.xml
@@ -0,0 +1,184 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.core
+ core-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-twitter-example
+ jar
+ HornetQ Twitter Example
+
+
+ consumerKey
+ consumerSecret
+ twitterAccess
+ twitterToken
+
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-commons
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnp-client
+ 5.0.5.Final
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+ default
+
+ true
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+ true
+ ${basedir}/target/classes/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ TWITTER_CONSUMER_KEY
+ ${TWITTER_CONSUMER_KEY}
+
+
+ TWITTER_CONSUMER_SECRET
+ ${TWITTER_CONSUMER_SECRET}
+
+
+ TWITTER_ACCESS_TOKEN
+ ${TWITTER_ACCESS_TOKEN}
+
+
+ TWITTER_ACCESS_TOKEN_SECRET
+ ${TWITTER_ACCESS_TOKEN_SECRET}
+
+
+
+
+
+
+ false
+ ${basedir}/target/classes/server0
+
+
+
+ org.hornetq.examples.core
+ hornetq-twitter-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-twitter-integration
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+
+
+
+
+ example
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.1
+
+
+ package
+
+ java
+
+
+
+
+ org.hornetq.core.example.TwitterConnectorExample
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/twitter-connector/readme.html b/examples/core/twitter-connector/readme.html
new file mode 100644
index 0000000000..7addfb4cfc
--- /dev/null
+++ b/examples/core/twitter-connector/readme.html
@@ -0,0 +1,96 @@
+
+
+ HornetQ Twitter Connector Service Example
+
+
+
+
+
+
Twitter Connector Service Example
+
+
This example shows you how to configure HornetQ to use the Twitter Connector Service.
+
+
HornetQ supports 2 types of Twitter connector, incoming and outgoing.
+ Incoming connector consumes from twitter and forwards to a configurable address.
+ Outgoing connector consumes from a configurable address and forwards to twitter.
+
+
+
In this example, incoming connector and outgoing connector is related to same twitter account.
+ So if you send a message to an outgoing address, outgoing connector forwards it to twitter,
+ and then incoming connector consumes it and forwards to incoming address.
+
+
Example step-by-step
+
To run the server, simply type mvn-Dtwitter.consumerKey=consumer -Dtwitter.consumerSecret=secret -Dtwitter.accessToken=token -Dtwitter.accessTokenSecret=secret verify
+ from this directory but replacing the system properties with those of the twitter account you want to use. Then run the example
+ by using the command mvn -Pexample package
+
+
+
+
First we need to create a ClientSessionFactory with Netty transport configuration
+ ClientConsumer cc = session.createConsumer(INCOMING_QUEUE);
+
+
+
We create a core message that we are going to send
+
+ ClientMessage cm = session.createMessage(org.hornetq.api.core.Message.TEXT_TYPE,true);
+String testMessage = System.currentTimeMillis() + ": twitter connector test example";
+cm.getBodyBuffer().writeString(testMessage);
+
+
+
We send the message to queue.outgoingQueue
+
+ cp.send(cm);
+
+
+
We start the session
+
+ session.start();
+
+
+
We will receive a message from queue.incomingQueue.
+ Outgoing connector forwards a message(we sent before) to twitter immediately.
+ Since incoming connector consumes from twitter and forwards to queue.incomingQueue
+ every 60 seconds, It will be received in 60+x seconds.
+
+
+
+
+
+
diff --git a/examples/core/twitter-connector/src/main/java/org/hornetq/core/example/TwitterConnectorExample.java b/examples/core/twitter-connector/src/main/java/org/hornetq/core/example/TwitterConnectorExample.java
new file mode 100644
index 0000000000..37274d1de9
--- /dev/null
+++ b/examples/core/twitter-connector/src/main/java/org/hornetq/core/example/TwitterConnectorExample.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClientConsumer;
+import org.hornetq.api.core.client.ClientMessage;
+import org.hornetq.api.core.client.ClientProducer;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.HornetQClient;
+import org.hornetq.api.core.client.ServerLocator;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+
+/**
+ * A simple example of using twitter connector service.
+ *
+ * @author Tomohisa Igarashi
+ */
+public class TwitterConnectorExample
+{
+ private static final String INCOMING_QUEUE = "queue.incomingQueue";
+ private static final String OUTGOING_QUEUE = "queue.outgoingQueue";
+
+ public static void main(final String[] args) throws Exception
+ {
+ ServerLocator locator = null;
+ ClientSessionFactory csf = null;
+ ClientSession session = null;
+ try
+ {
+ String testMessage = System.currentTimeMillis() + ": " + System.getProperty("twitter.example.alternativeMessage");
+ if(testMessage == null || testMessage.trim().equals("")) {
+ testMessage = System.currentTimeMillis() + ": ### Hello, HornetQ fans!! We are now experiencing so fast, so reliable and so exciting messaging never seen before ;-) ###";
+ }
+
+ // Step 1. Create a ClientSessionFactory
+
+
+ locator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName()));
+
+ csf = locator.createSessionFactory();
+
+ // Step 2. Create a core session.
+ session = csf.createSession(true,true);
+
+ // Step 3. Create a core producer for queue.outgoingQueue.
+ ClientProducer cp = session.createProducer(OUTGOING_QUEUE);
+
+ // Step 4. Create a core consumer for queue.incomingQueue.
+ ClientConsumer cc = session.createConsumer(INCOMING_QUEUE);
+
+ // Step 5. Create a core message.
+ ClientMessage cm = session.createMessage(org.hornetq.api.core.Message.TEXT_TYPE,true);
+ cm.getBodyBuffer().writeString(testMessage);
+
+ // Step 6. Send a message to queue.outgoingQueue.
+ cp.send(cm);
+ System.out.println("#### Sent a message to " + OUTGOING_QUEUE + ": " + testMessage);
+
+ // Step 7. Start the session.
+ session.start();
+
+ // Step 8. Receive a message from queue.incomingQueue.
+ // Outgoing connector forwards a message(sent at Step 6.) to twitter immediately.
+ // Since incoming connector consumes from twitter and forwards to queue.incomingQueue
+ // every 60 seconds, It will be received in 60+x seconds.
+ System.out.println("#### A message will be received in 60 seconds. Please wait...");
+ ClientMessage received = cc.receive(70 * 1000);
+ received.acknowledge();
+ String receivedText = received.getBodyBuffer().readString();
+
+ while(!receivedText.equals(testMessage))
+ {
+ // ignoring other tweets
+ received = cc.receiveImmediate();
+ if(received == null) {
+ // no other tweets. test message has gone...
+ return;
+ }
+
+ received.acknowledge();
+ receivedText = received.getBodyBuffer().readString();
+ }
+
+ System.out.println("#### Received a message from " + INCOMING_QUEUE + ": " + receivedText);
+ }
+ finally
+ {
+ // Step 9. Be sure to close some resources.
+ if(session != null)
+ {
+ session.close();
+ }
+ if(csf != null)
+ {
+ csf.close();
+ }
+
+ if (locator != null)
+ {
+ locator.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/core/twitter-connector/src/main/resources/server0/hornetq-beans.xml b/examples/core/twitter-connector/src/main/resources/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..171d3739eb
--- /dev/null
+++ b/examples/core/twitter-connector/src/main/resources/server0/hornetq-beans.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/core/twitter-connector/src/main/resources/server0/hornetq-configuration.xml b/examples/core/twitter-connector/src/main/resources/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..83cc84305d
--- /dev/null
+++ b/examples/core/twitter-connector/src/main/resources/server0/hornetq-configuration.xml
@@ -0,0 +1,71 @@
+
+
+
+ target/server0/data/messaging/bindings
+
+ target/server0/data/messaging/journal
+
+ target/server0/data/messaging/largemessages
+
+ target/server0/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ queue.incomingQueue
+
+
+ queue.outgoingQueue
+
+
+
+
+
+ org.hornetq.integration.twitter.TwitterIncomingConnectorServiceFactory
+
+
+
+
+
+
+
+
+ org.hornetq.integration.twitter.TwitterOutgoingConnectorServiceFactory
+
+
+
+
+
+
+
+
+
diff --git a/examples/core/twitter-connector/src/main/resources/server0/hornetq-jms.xml b/examples/core/twitter-connector/src/main/resources/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..678e7f5214
--- /dev/null
+++ b/examples/core/twitter-connector/src/main/resources/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/twitter-connector/src/main/resources/server0/hornetq-users.xml b/examples/core/twitter-connector/src/main/resources/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/core/twitter-connector/src/main/resources/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/vertx-connector/pom.xml b/examples/core/vertx-connector/pom.xml
new file mode 100644
index 0000000000..a2cc7f3935
--- /dev/null
+++ b/examples/core/vertx-connector/pom.xml
@@ -0,0 +1,181 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.core
+ core-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-vertx-example
+ jar
+ HornetQ Vert.x Example
+
+
+ 2.1RC1
+
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-commons
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnp-client
+ 5.0.5.Final
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+ io.vertx
+ vertx-core
+ ${vertx.version}
+ provided
+
+
+ io.vertx
+ vertx-platform
+ ${vertx.version}
+ provided
+
+
+ io.vertx
+ vertx-hazelcast
+ ${vertx.version}
+ provided
+
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.core.example.VertxConnectorExample
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.core
+ hornetq-vertx-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-vertx-integration
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+ io.vertx
+ vertx-core
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-platform
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-hazelcast
+ ${vertx.version}
+
+
+
+ false
+ ${basedir}/target/classes/server0
+
+
+
+
+
+
+
diff --git a/examples/core/vertx-connector/readme.html b/examples/core/vertx-connector/readme.html
new file mode 100644
index 0000000000..59538f9372
--- /dev/null
+++ b/examples/core/vertx-connector/readme.html
@@ -0,0 +1,84 @@
+
+
+ HornetQ Vert.x Connector Service Example
+
+
+
+
+
+
Vert.x Connector Service Example
+
+
This example shows you how to configure HornetQ to use the Vert.x Connector Service.
+
+
HornetQ supports 2 types of Vert.x connector, incoming and outgoing.
+ Incoming connector consumes from Vert.x event bus and forwards to a configurable address.
+ Outgoing connector consumes from a configurable address and forwards to a configurable Vert.x event bus.
+
+
+
In this example, an incoming connector and an outgoing connector are configured. A simple java Verticle
+ is deployed. The verticle registers a message handler on the outgoing connector's address ("outgoing.vertx.address").
+ A String message is sent to Vert.x event bus on the incoming connector's address("incoming.vertx.address").
+ The message then will be forwarded to a HornetQ queue by the incoming connector. The outgoing connector listens to
+ the HornetQ queue and forwards the message from HornetQ to Vert.x event bus on the outgoing connector's address.
+ The verticle finally receives the message from it's event bus.
+
+
For more information on Vert.x concept please visit the Vertx site
+
+
Example step-by-step
+
To run the server, simply type mvn verify
+ from this directory.
The message will eventually arrives at the Verticle's message handler.
+
+
+
diff --git a/examples/core/vertx-connector/src/main/java/org/hornetq/core/example/ExampleVerticle.java b/examples/core/vertx-connector/src/main/java/org/hornetq/core/example/ExampleVerticle.java
new file mode 100644
index 0000000000..9438434157
--- /dev/null
+++ b/examples/core/vertx-connector/src/main/java/org/hornetq/core/example/ExampleVerticle.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.vertx.java.core.Handler;
+import org.vertx.java.core.eventbus.EventBus;
+import org.vertx.java.core.eventbus.Message;
+import org.vertx.java.platform.Verticle;
+
+public class ExampleVerticle extends Verticle
+{
+ @Override
+ public void start()
+ {
+ EventBus eventBus = vertx.eventBus();
+
+ final CountDownLatch latch0 = new CountDownLatch(1);
+
+ // Register a handler on the outgoing connector's address
+ eventBus.registerHandler(VertxConnectorExample.OUTGOING,
+ new Handler>() {
+ @Override
+ public void handle(Message> startMsg)
+ {
+ Object body = startMsg.body();
+ System.out.println("Verticle receives a message: " + body);
+ VertxConnectorExample.result.set(VertxConnectorExample.MSG.equals(body));
+ latch0.countDown();
+ //Tell the example to finish.
+ VertxConnectorExample.latch.countDown();
+ }
+ });
+
+ try
+ {
+ latch0.await(5000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+}
diff --git a/examples/core/vertx-connector/src/main/java/org/hornetq/core/example/VertxConnectorExample.java b/examples/core/vertx-connector/src/main/java/org/hornetq/core/example/VertxConnectorExample.java
new file mode 100644
index 0000000000..12a1e8b458
--- /dev/null
+++ b/examples/core/vertx-connector/src/main/java/org/hornetq/core/example/VertxConnectorExample.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.core.example;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.vertx.java.core.AsyncResult;
+import org.vertx.java.core.Handler;
+import org.vertx.java.core.eventbus.EventBus;
+import org.vertx.java.platform.PlatformLocator;
+import org.vertx.java.platform.PlatformManager;
+import org.vertx.java.spi.cluster.impl.hazelcast.HazelcastClusterManagerFactory;
+
+/**
+ * A simple example of using Vert.x connector service.
+ *
+ * @author Howard Gao
+ */
+public class VertxConnectorExample
+{
+ public static final String INCOMING = "incoming.vertx.address";
+ public static final String OUTGOING = "outgoing.vertx.address";
+ public static final String MSG = "Welcome to Vertx world!";
+
+ public final static CountDownLatch latch = new CountDownLatch(1);
+ public final static AtomicBoolean result = new AtomicBoolean(false);
+
+ private static final String HOST = "127.0.0.1";
+ private static final int PORT = 0;
+
+ public static void main(final String[] args) throws Exception
+ {
+ System.setProperty("vertx.clusterManagerFactory",
+ HazelcastClusterManagerFactory.class.getName());
+ PlatformManager platformManager = null;
+
+ try
+ {
+ // Step 1 Create a Vert.x PlatformManager
+ platformManager = PlatformLocator.factory.createPlatformManager(PORT, HOST);
+
+ final CountDownLatch latch0 = new CountDownLatch(1);
+
+ // Step 2 Deploy a Verticle to receive message
+ String verticle = "org.hornetq.core.example.ExampleVerticle";
+ platformManager.deployVerticle(verticle, null, new URL[0], 1, null,
+ new Handler>(){
+
+ @Override
+ public void handle(AsyncResult result)
+ {
+ if (!result.succeeded())
+ {
+ throw new RuntimeException("failed to deploy verticle", result.cause());
+ }
+ latch0.countDown();
+ }
+
+ });
+
+ latch0.await();
+
+ // Step 3 Send a message to the incoming connector's address
+ EventBus bus = platformManager.vertx().eventBus();
+ bus.send(INCOMING, MSG);
+
+ // Step 4 Waiting for the Verticle to process the message
+ latch.await(10000, TimeUnit.MILLISECONDS);
+ }
+ finally
+ {
+ if(platformManager != null)
+ {
+ platformManager.undeployAll(null);
+ platformManager.stop();
+ }
+ reportResultAndExit();
+ }
+ }
+
+ private static void reportResultAndExit()
+ {
+ if (!result.get())
+ {
+ System.err.println();
+ System.err.println("#####################");
+ System.err.println("### FAILURE! ###");
+ System.err.println("#####################");
+ System.exit(1);
+ }
+ else
+ {
+ System.out.println();
+ System.out.println("#####################");
+ System.out.println("### SUCCESS! ###");
+ System.out.println("#####################");
+ System.exit(0);
+ }
+ }
+
+}
diff --git a/examples/core/vertx-connector/src/main/resources/server0/hornetq-beans.xml b/examples/core/vertx-connector/src/main/resources/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..171d3739eb
--- /dev/null
+++ b/examples/core/vertx-connector/src/main/resources/server0/hornetq-beans.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/core/vertx-connector/src/main/resources/server0/hornetq-configuration.xml b/examples/core/vertx-connector/src/main/resources/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..32df46609b
--- /dev/null
+++ b/examples/core/vertx-connector/src/main/resources/server0/hornetq-configuration.xml
@@ -0,0 +1,61 @@
+
+
+
+ target/server0/data/messaging/bindings
+
+ target/server0/data/messaging/journal
+
+ target/server0/data/messaging/largemessages
+
+ target/server0/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ queue.vertxQueue
+
+
+
+
+
+ org.hornetq.integration.vertx.VertxIncomingConnectorServiceFactory
+
+
+
+
+
+
+ org.hornetq.integration.vertx.VertxOutgoingConnectorServiceFactory
+
+
+
+
+
+
+
+
diff --git a/examples/core/vertx-connector/src/main/resources/server0/hornetq-jms.xml b/examples/core/vertx-connector/src/main/resources/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..678e7f5214
--- /dev/null
+++ b/examples/core/vertx-connector/src/main/resources/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/core/vertx-connector/src/main/resources/server0/hornetq-users.xml b/examples/core/vertx-connector/src/main/resources/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/core/vertx-connector/src/main/resources/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/README.md b/examples/javaee/README.md
new file mode 100644
index 0000000000..faa5a5aba1
--- /dev/null
+++ b/examples/javaee/README.md
@@ -0,0 +1,12 @@
+Running the Java EE examples
+========================
+
+To run a javaee example first make sure you have WildFly installed, the examples were tested against against [8.0.0.Final](http://wildfly.org/downloads/).
+
+Then set the JBOSS_HOME property to your installation, something like:
+
+export JBOSS_HOME=/home/user/wildfly-8.0.0.Final
+
+Then simply cd into the directory of the example you want to run and 'mvn test'.
+
+The examples use [Arquillian](http://www.jboss.org/arquillian.html) to start the JBoss server and to run the example itself.
\ No newline at end of file
diff --git a/examples/javaee/ejb-jms-transaction/pom.xml b/examples/javaee/ejb-jms-transaction/pom.xml
new file mode 100644
index 0000000000..4d09102e74
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-ejb-jms-example
+ jar
+ HornetQ Java EE MDB EJB Transaction Example
+
\ No newline at end of file
diff --git a/examples/javaee/ejb-jms-transaction/readme.html b/examples/javaee/ejb-jms-transaction/readme.html
new file mode 100644
index 0000000000..85bbed9f90
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/readme.html
@@ -0,0 +1,203 @@
+
+
+ HornetQ EJB/JMS Transaction Example
+
+
+
+
+
+
EJB/JMS Transaction Example
+
+
The example application will invoke an EJB which is deployed within WildFly which will:
+
+
start an XA transaction
+
send a JMS message
+
update an in-memory database
+
commit the transaction
+
+
The example application will then receive the message sent by the EJB.
+
+
WildFly configuration
+
+
The example leverages the Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
The example code is composed of two main classes:
+
+
EJBClientExample
- the example application
+
SendMessageBean
- a Stateless EJB with a remote interface
+
+
+
Example Application
+
+
Let's take a look at EJBClientExample first.
+
+
+
First we need to get an initial context so we can look-up the EJB. This initial context will get it's properties from the jboss-ejb-client.properties.
+
+ Properties env = new Properties();
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ InitialContext initialContext = new InitialContext();
+
+
+
We look up the EJB
+
+ SendMessageService service = (SendMessageService) initialContext.lookup("ejb:/test//SendMessageBean!org.hornetq.javaee.example.server.SendMessageService");
+
+
+
We create the DB table which will be updated if it does not already exist
+
+ service.createTable();
+
+
+
We invoke the EJB's sendAndUpdate method. This method will send a JMS text message (with the text passed in parameter)
+ and insert a row in the database table with the text and the message's JMS Message ID
+
+ service.sendAndUpdate("This is a text message");
+
+
+
We will now consume the JMS message which was sent by the EJB at step 4.
+
+
We need to get a new initial context so we can look-up the JMS connection factory and destination objects from JNDI.
+
+ env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+ initialContext = new InitialContext(env);
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/ejb-jms-transaction/server/standalone/configuration/application-roles.properties b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/ejb-jms-transaction/server/standalone/configuration/application-users.properties b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/ejb-jms-transaction/server/standalone/configuration/logging.properties b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/ejb-jms-transaction/server/standalone/configuration/mgmt-users.properties b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/ejb-jms-transaction/server/standalone/configuration/standalone-example.xml b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..e2d45af14b
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,502 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+ h2
+ jdbc:h2:mem:test
+
+ 10
+ 20
+ true
+
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/EJBClientExample.java b/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/EJBClientExample.java
new file mode 100644
index 0000000000..5d9b979795
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/EJBClientExample.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+import org.hornetq.javaee.example.server.SendMessageService;
+
+/**
+ * An example showing how to invoke a EJB which sends a JMS message and update a JDBC table in the same transaction.
+ *
+ * @author Andy Taylor
+ * @author Jeff Mesnil
+ * @author Justin Bertram
+ */
+public class EJBClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ InitialContext initialContext = null;
+ Connection connection = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the EJB lookup.
+ Properties env = new Properties();
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ initialContext = new InitialContext(env);
+
+ // Step 2. Lookup the EJB
+ SendMessageService service = (SendMessageService) initialContext.lookup("ejb:/test//SendMessageBean!org.hornetq.javaee.example.server.SendMessageService");
+
+ // Step 3. Create the DB table which will be updated
+ service.createTable();
+
+ // Step 4. Invoke the sendAndUpdate method
+ service.sendAndUpdate("This is a text message");
+ System.out.println("invoked the EJB service");
+
+ // Step 5. Create a new initial context for the JMS JNDI look-ups.
+ env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+ initialContext = new InitialContext(env);
+
+ // Step 6. Lookup the JMS connection factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ // Step 7. Lookup the queue
+ Queue queue = (Queue) initialContext.lookup("jms/queues/testQueue");
+
+ // Step 8. Create a connection, a session and a message consumer for the queue
+ connection = cf.createConnection("guest", "password");
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ // Step 9. Start the connection
+ connection.start();
+
+ // Step 10. Receive the message sent by the EJB
+ TextMessage messageReceived = (TextMessage) consumer.receive(5000);
+ System.out.println("Received message: " + messageReceived.getText() + " (" + messageReceived.getJMSMessageID() + ")");
+ }
+ finally
+ {
+ // Step 11. Be sure to close the resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/server/SendMessageBean.java b/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/server/SendMessageBean.java
new file mode 100644
index 0000000000..d454447325
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/server/SendMessageBean.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import java.sql.PreparedStatement;
+
+import javax.ejb.Remote;
+import javax.ejb.Stateless;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+
+/**
+ * An EJB which sends a JMS message and update a JDBC table in the same transaction.
+ *
+ * @author Andy Taylor
+ * @author Jeff Mesnil
+ */
+@Stateless
+@Remote(SendMessageService.class)
+public class SendMessageBean implements SendMessageService
+{
+
+ private static final String TABLE = "hornetq_example";
+
+ public void createTable() throws Exception
+ {
+ InitialContext ic = new InitialContext();
+ DataSource ds = (DataSource)ic.lookup("java:jboss/datasources/ExampleDS");
+ java.sql.Connection con = ds.getConnection();
+
+ // check if the table exists:
+ boolean createTable = false;
+ try
+ {
+ PreparedStatement pr = con.prepareStatement("SELECT * FROM " + SendMessageBean.TABLE + ";");
+ pr.executeQuery();
+ pr.close();
+ }
+ catch (Exception e)
+ {
+ createTable = true;
+ }
+
+ if (createTable)
+ {
+ PreparedStatement pr = con.prepareStatement("CREATE TABLE " + SendMessageBean.TABLE +
+ "(id VARCHAR(100), text VARCHAR(100));");
+ pr.execute();
+ pr.close();
+ System.out.println("Table " + SendMessageBean.TABLE + " created");
+ }
+
+ con.close();
+ }
+
+ public void sendAndUpdate(final String text) throws Exception
+ {
+ InitialContext ic = null;
+ Connection jmsConnection = null;
+ java.sql.Connection jdbcConnection = null;
+
+ try
+ {
+ // Step 1. Lookup the initial context
+ ic = new InitialContext();
+
+ // JMS operations
+
+ // Step 2. Look up the XA Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)ic.lookup("java:/JmsXA");
+
+ // Step 3. Look up the Queue
+ Queue queue = (Queue)ic.lookup("queue/testQueue");
+
+ // Step 4. Create a connection, a session and a message producer for the queue
+ jmsConnection = cf.createConnection();
+ Session session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer messageProducer = session.createProducer(queue);
+
+ // Step 5. Create a Text Message
+ TextMessage message = session.createTextMessage(text);
+
+ // Step 6. Send The Text Message
+ messageProducer.send(message);
+ System.out.println("Sent message: " + message.getText() + "(" + message.getJMSMessageID() + ")");
+
+ // DB operations
+
+ // Step 7. Look up the XA Data Source
+ DataSource ds = (DataSource)ic.lookup("java:jboss/datasources/XADS");
+
+ // Step 8. Retrieve the JDBC connection
+ jdbcConnection = ds.getConnection();
+
+ // Step 9. Create the prepared statement to insert the text and the message's ID in the table
+ PreparedStatement pr = jdbcConnection.prepareStatement("INSERT INTO " + SendMessageBean.TABLE +
+ " (id, text) VALUES ('" +
+ message.getJMSMessageID() +
+ "', '" +
+ text +
+ "');");
+
+ // Step 10. execute the prepared statement
+ pr.execute();
+
+ // Step 11. close the prepared statement
+ pr.close();
+ }
+ finally
+ {
+ // Step 12. Be sure to close all resources!
+ if (ic != null)
+ {
+ ic.close();
+ }
+ if (jmsConnection != null)
+ {
+ jmsConnection.close();
+ }
+ if (jdbcConnection != null)
+ {
+ jdbcConnection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/server/SendMessageService.java b/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/server/SendMessageService.java
new file mode 100644
index 0000000000..aecd8a91c5
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/src/main/java/org/hornetq/javaee/example/server/SendMessageService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+/**
+ * The interface of an EJB which sends a JMS message and updates a JDBC table in the same transaction.
+ *
+ * @author Andy Taylor
+ */
+public interface SendMessageService
+{
+ void sendAndUpdate(String text) throws Exception;
+
+ void createTable() throws Exception;
+
+}
diff --git a/examples/javaee/ejb-jms-transaction/src/main/resources/jboss-ejb-client.properties b/examples/javaee/ejb-jms-transaction/src/main/resources/jboss-ejb-client.properties
new file mode 100644
index 0000000000..fcf57ba3c0
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/src/main/resources/jboss-ejb-client.properties
@@ -0,0 +1,7 @@
+remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
+
+remote.connections=default
+
+remote.connection.default.host=localhost
+remote.connection.default.port = 8080
+remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
\ No newline at end of file
diff --git a/examples/javaee/ejb-jms-transaction/src/test/java/org/hornetq/javaee/examples/MDBEJBTXRequiredRunnerTest.java b/examples/javaee/ejb-jms-transaction/src/test/java/org/hornetq/javaee/examples/MDBEJBTXRequiredRunnerTest.java
new file mode 100644
index 0000000000..8cce9bd05f
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/src/test/java/org/hornetq/javaee/examples/MDBEJBTXRequiredRunnerTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.EJBClientExample;
+import org.hornetq.javaee.example.server.SendMessageBean;
+import org.hornetq.javaee.example.server.SendMessageService;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBEJBTXRequiredRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "ejb.jar");
+ ejbJar.addClass(SendMessageBean.class);
+ ejbJar.addClass(SendMessageService.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ EJBClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(10000);
+ }
+}
diff --git a/examples/javaee/ejb-jms-transaction/src/test/resources/arquillian.xml b/examples/javaee/ejb-jms-transaction/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..1aada30255
--- /dev/null
+++ b/examples/javaee/ejb-jms-transaction/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-config/pom.xml b/examples/javaee/jca-config/pom.xml
new file mode 100644
index 0000000000..dca8852095
--- /dev/null
+++ b/examples/javaee/jca-config/pom.xml
@@ -0,0 +1,64 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-jca-config-example
+ jar
+ HornetQ Java EE JCA Config Example
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ as-node1
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node1
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12
+
+ -Dlogging.configuration=file:///${user.dir}/test/config/logging.properties
+
+
+ clustering-all
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-config/readme.html b/examples/javaee/jca-config/readme.html
new file mode 100644
index 0000000000..d88ab7ac1e
--- /dev/null
+++ b/examples/javaee/jca-config/readme.html
@@ -0,0 +1,109 @@
+
+
+ HornetQ Java EE JCA Configuration Example
+
+
+
+
+
+
Java EE Resource Adapter Configuration Example
+
+
This example demonstrates how to configure several properties on the HornetQ Resource Adapter. We setup two
+ WildFly. The enterprise application is being deployed in one application server while the MDBs and JMS
+ Connections are pointing to a remote server
+
This example is composed of two message-driven beans (MDB), MDBQueueA and MDBQueueB, and a stateless session
+ bean StatelessSender, and a main class MDBRemoteClientExample.
+
MDBRemoteClientExample will invoke the StatelessSender bean on the second server which will in turn send a
+ message to 2 queues on the first server which will then be consumed by each MDB.
+
MDBQueueA consumes the message locally.
+
MDBQueueB is on the second server who's JCA Adapter is configured to consume remotely from the first server
+
+
WildFly configuration
+
+
The example leverages the Arquillian framework to run multiple WildFly instances and deploy the MDBs and SLSB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the EJB. This initial context will get it's properties from the jboss-ejb-client.properties.
+
+ Properties env = new Properties();
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ initialContext = new InitialContext(env);
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-config/server/standalone/configuration/application-roles.properties b/examples/javaee/jca-config/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/jca-config/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/jca-config/server/standalone/configuration/application-users.properties b/examples/javaee/jca-config/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/jca-config/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/jca-config/server/standalone/configuration/logging.properties b/examples/javaee/jca-config/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/jca-config/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/jca-config/server/standalone/configuration/mgmt-users.properties b/examples/javaee/jca-config/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/jca-config/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/jca-config/server/standalone/configuration/standalone-example.xml b/examples/javaee/jca-config/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..fc153645ad
--- /dev/null
+++ b/examples/javaee/jca-config/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-config/server/standalone/configuration/standalone-example2.xml b/examples/javaee/jca-config/server/standalone/configuration/standalone-example2.xml
new file mode 100644
index 0000000000..faf3f3f000
--- /dev/null
+++ b/examples/javaee/jca-config/server/standalone/configuration/standalone-example2.xml
@@ -0,0 +1,496 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ guest
+ password
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/MDBRemoteClientExample.java b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/MDBRemoteClientExample.java
new file mode 100644
index 0000000000..67b77ca312
--- /dev/null
+++ b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/MDBRemoteClientExample.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server2.StatelessSenderService;
+
+import javax.jms.Connection;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ *
+ * MDB Remote & JCA Configuration Example.
+ *
+ * @author Clebert Suconic
+ */
+public class MDBRemoteClientExample
+{
+ public static void main(String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the EJB lookup.
+ Properties env = new Properties();
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ initialContext = new InitialContext(env);
+
+ // Step 2. Lookup the EJB
+ StatelessSenderService sender = (StatelessSenderService)initialContext.lookup("ejb:/test//StatelessSender!org.hornetq.javaee.example.server2.StatelessSenderService");
+
+ //Step 3. Calling a Stateless Session Bean. You will have more steps on the SessionBean
+ sender.sendHello("Hello there MDB!");
+
+ System.out.println("Step 3: Invoking the Stateless Bean");
+
+ initialContext.close();
+ }
+ finally
+ {
+ //Step 11. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if(connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server/MDBQueueA.java b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server/MDBQueueA.java
new file mode 100644
index 0000000000..1ea3e74c72
--- /dev/null
+++ b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server/MDBQueueA.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+/**
+ * MDB that is connected to the remote queue.
+ * @author Clebert Suconic
+ */
+
+//Step 9. The message is received on the MDB, using a local queue.
+@MessageDriven(name = "MDB_QueueA",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/A")
+ })
+public class MDBQueueA implements MessageListener
+{
+ public void onMessage(Message message)
+ {
+ try
+ {
+ TextMessage tm = (TextMessage)message;
+
+ String text = tm.getText();
+
+ System.out.println("Step 10: (MDBQueueA.java) Message received using the default adapter. Message = \"" + text + "\"" );
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/MDBQueueB.java b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/MDBQueueB.java
new file mode 100644
index 0000000000..763541947f
--- /dev/null
+++ b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/MDBQueueB.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server2;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+/**
+ * MDB that is connected to the remote queue.
+ * @author Clebert Suconic
+ */
+
+//Step 10. The message is received on the MDB, using a remote queue.
+@MessageDriven(name = "MDB_QueueB",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "B"),
+ @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false")
+ })
+@ResourceAdapter("hornetq-ra-remote.rar")
+public class MDBQueueB implements MessageListener
+{
+ public void onMessage(Message message)
+ {
+ try
+ {
+ TextMessage tm = (TextMessage)message;
+
+ String text = tm.getText();
+
+ System.out.println("Step 11: (MDBQueueB.java) Message received using the remote adapter. Message = \"" + text + "\"" );
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/StatelessSender.java b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/StatelessSender.java
new file mode 100644
index 0000000000..f2409c06fc
--- /dev/null
+++ b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/StatelessSender.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server2;
+
+import org.hornetq.api.jms.HornetQJMSClient;
+import org.hornetq.ra.HornetQRAConnectionFactoryImpl;
+
+import javax.annotation.Resource;
+import javax.ejb.Remote;
+import javax.ejb.Stateless;
+import javax.jms.*;
+
+/**
+ * A Stateless Bean that will connect to a remote JBM.
+ *
+ * @author Clebert Suconic
+ */
+@Remote(StatelessSenderService.class)
+@Stateless
+public class StatelessSender implements StatelessSenderService
+{
+ @Resource(mappedName="java:/RemoteJmsXA")
+ private ConnectionFactory connectionFactory;
+
+ public void sendHello(String message) throws Exception
+ {
+ // Step 4. Define the destinations that will receive the message (instead of using JNDI to the remote server)
+ Queue destQueueA = HornetQJMSClient.createQueue("A");
+ Queue destQueueB = HornetQJMSClient.createQueue("B");
+ // Step 5. Create a connection to a remote server using a connection-factory (look at the deployed file jms-remote-ds.xml)
+ Connection conn = connectionFactory.createConnection("guest", "password");
+
+ // Step 6. Send a message to a QueueA on the remote server, which will be received by MDBQueueA
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer prodA = sess.createProducer(destQueueA);
+ prodA.send(sess.createTextMessage(message));
+
+ // Step 7. Send a message to a QueueB on the remote server, which will be received by MDBQueueA
+ MessageProducer prodB = sess.createProducer(destQueueB);
+ prodB.send(sess.createTextMessage(message));
+
+ // Step 8. Close the connection. (Since this is a JCA connection, this will just place the connection back to a connection pool)
+ conn.close();
+ }
+}
diff --git a/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/StatelessSenderService.java b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/StatelessSenderService.java
new file mode 100644
index 0000000000..6222474b2e
--- /dev/null
+++ b/examples/javaee/jca-config/src/main/java/org/hornetq/javaee/example/server2/StatelessSenderService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.example.server2;
+
+/**
+ * A StatelessSenderService
+ *
+ * @author Clebert Suconic
+ *
+ *
+ */
+public interface StatelessSenderService
+{
+
+ public void sendHello(String message) throws Exception;
+
+}
diff --git a/examples/javaee/jca-config/src/main/resources/jboss-ejb-client.properties b/examples/javaee/jca-config/src/main/resources/jboss-ejb-client.properties
new file mode 100644
index 0000000000..f31d4413a9
--- /dev/null
+++ b/examples/javaee/jca-config/src/main/resources/jboss-ejb-client.properties
@@ -0,0 +1,7 @@
+remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
+
+remote.connections=default
+
+remote.connection.default.host=localhost
+remote.connection.default.port = 8180
+remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
\ No newline at end of file
diff --git a/examples/javaee/jca-config/src/test/java/org/hornetq/javaee/example/server/ExampleRunner2Test.java b/examples/javaee/jca-config/src/test/java/org/hornetq/javaee/example/server/ExampleRunner2Test.java
new file mode 100644
index 0000000000..72fd4aa79a
--- /dev/null
+++ b/examples/javaee/jca-config/src/test/java/org/hornetq/javaee/example/server/ExampleRunner2Test.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.hornetq.javaee.example.MDBRemoteClientExample;
+import org.hornetq.javaee.example.server2.MDBQueueB;
+import org.hornetq.javaee.example.server2.StatelessSender;
+import org.hornetq.javaee.example.server2.StatelessSenderService;
+import org.jboss.arquillian.container.test.api.ContainerController;
+import org.jboss.arquillian.container.test.api.Deployer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.junit.InSequence;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class ExampleRunner2Test
+{
+ @ArquillianResource
+ private ContainerController controller;
+ @ArquillianResource
+ private Deployer deployer;
+
+ @Deployment(name = "deploy-0", managed = false)
+ @TargetsContainer("node-0")
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDBQueueA.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Deployment(name = "deploy-1", managed = false)
+ @TargetsContainer("node-1")
+ public static Archive getDeployment2()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb2.jar");
+ ejbJar.addClass(MDBQueueB.class);
+ ejbJar.addClass(StatelessSenderService.class);
+ ejbJar.addClass(StatelessSender.class);
+
+ final WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war");
+ war.addAsManifestResource("jboss-deployment-structure.xml", "jboss-deployment-structure.xml");
+ war.addAsLibrary(ejbJar);
+ System.out.println(war.toString(true));
+ return war;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDBRemoteClientExample.main(null);
+ }
+
+ @Test
+ @InSequence(-1)
+ public void startServer()
+ {
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-0");
+ System.out.println("*****************************************************************************************************************************************************************");
+ deployer.deploy("deploy-0");
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-1");
+ System.out.println("*****************************************************************************************************************************************************************");
+ deployer.deploy("deploy-1");
+ System.out.println("*****************************************************************************************************************************************************************");
+ }
+
+ @Test
+ @InSequence(1)
+ public void stopServer()
+ {
+ deployer.undeploy("deploy-1");
+ controller.stop("node-1");
+ deployer.undeploy("deploy-0");
+ controller.stop("node-0");
+ }
+}
diff --git a/examples/javaee/jca-config/src/test/resources/arquillian.xml b/examples/javaee/jca-config/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..33b56aa204
--- /dev/null
+++ b/examples/javaee/jca-config/src/test/resources/arquillian.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ -Djboss.node.name=node-0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+ ${basedir}/target/jbossas-node1
+ -Djboss.node.name=node-1 -Djboss.socket.binding.port-offset=100
+ standalone-example2.xml
+ true
+ ${node0:127.0.0.1}
+ ${as.managementPort:10090}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-config/src/test/resources/jboss-deployment-structure.xml b/examples/javaee/jca-config/src/test/resources/jboss-deployment-structure.xml
new file mode 100644
index 0000000000..5bd26f867f
--- /dev/null
+++ b/examples/javaee/jca-config/src/test/resources/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-remote/pom.xml b/examples/javaee/jca-remote/pom.xml
new file mode 100644
index 0000000000..95d079acb3
--- /dev/null
+++ b/examples/javaee/jca-remote/pom.xml
@@ -0,0 +1,64 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-jca-remote-example
+ jar
+ HornetQ Java EE JCA Remote Example
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ as-node1
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node1
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12
+
+ -Dlogging.configuration=file:///${user.dir}/test/config/logging.properties
+
+
+ clustering-all
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-remote/readme.html b/examples/javaee/jca-remote/readme.html
new file mode 100644
index 0000000000..80518a6859
--- /dev/null
+++ b/examples/javaee/jca-remote/readme.html
@@ -0,0 +1,160 @@
+
+
+ HornetQ Java EE JCA Remote Server Configuration Example
+
+
+
+
+
+
Java EE JCA Resource Adapter Remote Server Configuration Example
+
This example demonstrates how to configure the Resource adapter to connect to a remote HornetQ server
+
This example is composed of a message driven bean and a client
+
MDBRemoteServerClientExample will send a message to the MDB via a queue and wait for the MDB to send a response via
+ a reply queue
+
+
WildFly configuration
+
+
The example leverages the Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Configuring the incoming JCA resource adapter
+
+
The MDB will consume messages via the inflow JCA resource adapter. This can be configured in 2 ways:
+
+
via a pooled-connection-factory in the "messaging" subsystem
+
via the activation configuration properties on the MDB set either via annotations or ejb-jar.xml
+
+
In this example the MDB is annotated with @ResourceAdapter("hornetq-ra-remote.rar") which refers to
+ this pooled-connection-factory:
This configuration ensures the MDB will consume from the remote queue.
+
+
Configuring the outgoing JCA resource adapter
+
+
The same pooled-connection-factory used for JCA inflow also configures an outgoing JCA connection factory which Java EE components can use to send messages to the same remote HornetQ Server.
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-remote/server/standalone/configuration/application-roles.properties b/examples/javaee/jca-remote/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/jca-remote/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/jca-remote/server/standalone/configuration/application-users.properties b/examples/javaee/jca-remote/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/jca-remote/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/jca-remote/server/standalone/configuration/logging.properties b/examples/javaee/jca-remote/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/jca-remote/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/jca-remote/server/standalone/configuration/mgmt-users.properties b/examples/javaee/jca-remote/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..309305ab16
--- /dev/null
+++ b/examples/javaee/jca-remote/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=ffd6e94a09c5a9ea5e216737dd45b99d
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/jca-remote/server/standalone/configuration/standalone-example.xml b/examples/javaee/jca-remote/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..f6038107b9
--- /dev/null
+++ b/examples/javaee/jca-remote/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,496 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ guest
+ password
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/jca-remote/server/standalone/configuration/standalone-example2.xml b/examples/javaee/jca-remote/server/standalone/configuration/standalone-example2.xml
new file mode 100644
index 0000000000..2885355f1e
--- /dev/null
+++ b/examples/javaee/jca-remote/server/standalone/configuration/standalone-example2.xml
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/jca-remote/src/main/java/org/hornetq/javaee/example/MDBRemoteServerClientExample.java b/examples/javaee/jca-remote/src/main/java/org/hornetq/javaee/example/MDBRemoteServerClientExample.java
new file mode 100644
index 0000000000..1aad6ced48
--- /dev/null
+++ b/examples/javaee/jca-remote/src/main/java/org/hornetq/javaee/example/MDBRemoteServerClientExample.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ *
+ * MDB Remote & JCA Configuration Example.
+ *
+ * @author Clebert Suconic
+ */
+public class MDBRemoteServerClientExample
+{
+ public static void main(String[] args) throws Exception
+ {
+ InitialContext initialContext = null;
+ Connection connection = null;
+ try
+ {
+ //Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8180");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Look up the MDB's queue
+ Queue queue = (Queue) initialContext.lookup("queues/mdbQueue");
+
+ // Step 3. Look up a Connection Factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ //Step 4. Create a connection
+ connection = cf.createConnection("guest", "password");
+
+ //Step 5. Create a Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a message producer to send the message
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create and send a message
+ producer.send(session.createTextMessage("a message"));
+
+ // Step 15. Look up the reply queue
+ Queue replyQueue = (Queue) initialContext.lookup("queues/mdbReplyQueue");
+
+ // Step 16. Create a message consumer to receive the message
+ MessageConsumer consumer = session.createConsumer(replyQueue);
+
+ // Step 17. Start the connection so delivery starts
+ connection.start();
+
+ // Step 18. Receive the text message
+ TextMessage textMessage = (TextMessage) consumer.receive(5000);
+
+ System.out.println("Message received from reply queue. Message = \"" + textMessage.getText() + "\"" );
+
+ }
+ finally
+ {
+ // Step 19. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/jca-remote/src/main/java/org/hornetq/javaee/example/server/MDBQueue.java b/examples/javaee/jca-remote/src/main/java/org/hornetq/javaee/example/server/MDBQueue.java
new file mode 100644
index 0000000000..b6e9aa604f
--- /dev/null
+++ b/examples/javaee/jca-remote/src/main/java/org/hornetq/javaee/example/server/MDBQueue.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.hornetq.api.jms.HornetQJMSClient;
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.*;
+
+/**
+ * MDB that is connected to the remote queue.
+ * @author Clebert Suconic
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@MessageDriven(name = "MDB_Queue",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "mdbQueue"),
+ @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false")
+ })
+@ResourceAdapter("hornetq-ra-remote.rar")
+public class MDBQueue implements MessageListener
+{
+ @Resource(mappedName="java:/RemoteJmsXA")
+ private ConnectionFactory connectionFactory;
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ // Step 8. Receive the text message
+ TextMessage tm = (TextMessage)message;
+
+ String text = tm.getText();
+
+ // Step 9. look up the reply queue
+ Queue destQueue = HornetQJMSClient.createQueue("mdbReplyQueue");
+
+ // Step 10. Create a connection
+ Connection connection = connectionFactory.createConnection();
+
+ // Step 11. Create a session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 12. Create a message producer to send the message
+ MessageProducer producer = session.createProducer(destQueue);
+
+ // Step 13. Create and send a reply text message
+ producer.send(session.createTextMessage("A reply message"));
+
+ // Step 14. Return the connection back to the pool
+ connection.close();
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/jca-remote/src/test/java/org/hornetq/javaee/examples/JCARemoteRunnerTest.java b/examples/javaee/jca-remote/src/test/java/org/hornetq/javaee/examples/JCARemoteRunnerTest.java
new file mode 100644
index 0000000000..c610f03083
--- /dev/null
+++ b/examples/javaee/jca-remote/src/test/java/org/hornetq/javaee/examples/JCARemoteRunnerTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.MDBRemoteServerClientExample;
+import org.hornetq.javaee.example.server.MDBQueue;
+import org.jboss.arquillian.container.test.api.ContainerController;
+import org.jboss.arquillian.container.test.api.Deployer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.junit.InSequence;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class JCARemoteRunnerTest
+{
+ @ArquillianResource
+ private ContainerController controller;
+ @ArquillianResource
+ private Deployer deployer;
+
+ @Deployment(name = "deploy-0", managed = false)
+ @TargetsContainer("node-0")
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDBQueue.class);
+
+ final WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war");
+ war.addAsManifestResource("jboss-deployment-structure.xml", "jboss-deployment-structure.xml");
+ war.addAsLibrary(ejbJar);
+ System.out.println(war.toString(true));
+ return war;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDBRemoteServerClientExample.main(null);
+ }
+
+ @Test
+ @InSequence(-1)
+ public void startServer()
+ {
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-1");
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-0");
+ System.out.println("*****************************************************************************************************************************************************************");
+ deployer.deploy("deploy-0");
+ }
+
+ @Test
+ @InSequence(1)
+ public void stopServer()
+ {
+ deployer.undeploy("deploy-0");
+ controller.stop("node-0");
+ controller.stop("node-1");
+ }
+
+}
diff --git a/examples/javaee/jca-remote/src/test/resources/arquillian.xml b/examples/javaee/jca-remote/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..f1338eade7
--- /dev/null
+++ b/examples/javaee/jca-remote/src/test/resources/arquillian.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ -Djboss.node.name=node-0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+ ${basedir}/target/jbossas-node1
+ -Djboss.node.name=node-1 -Djboss.socket.binding.port-offset=100
+ standalone-example2.xml
+ true
+ ${node0:127.0.0.1}
+ ${as.managementPort:10090}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jca-remote/src/test/resources/jboss-deployment-structure.xml b/examples/javaee/jca-remote/src/test/resources/jboss-deployment-structure.xml
new file mode 100644
index 0000000000..5bd26f867f
--- /dev/null
+++ b/examples/javaee/jca-remote/src/test/resources/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jms-bridge/pom.xml b/examples/javaee/jms-bridge/pom.xml
new file mode 100644
index 0000000000..cf319be1d0
--- /dev/null
+++ b/examples/javaee/jms-bridge/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-bridge-example
+ jar
+ HornetQ JMS Bridge Example
+
\ No newline at end of file
diff --git a/examples/javaee/jms-bridge/readme.html b/examples/javaee/jms-bridge/readme.html
new file mode 100644
index 0000000000..bf64790e20
--- /dev/null
+++ b/examples/javaee/jms-bridge/readme.html
@@ -0,0 +1,168 @@
+
+
+ HornetQ JMS Bridge Example
+
+
+
+
+
+
JMS Bridge Example
+
+
This example shows how to configure and run a JMS Bridge in WildFly.
+ A bridge receives messages from a source JMS destination and forwards them to a target destination.
+
The source and target destinations can be on different servers, even from different JMS providers. For example, you can use this
+ JMS Bridge to bridge a legacy JMS provider to HornetQ during migration.
+
+
This example will show how to configure and run the simplest bridge:
+
+
the source and target destinations are hosted by a single WildFly instance
+
the bridge is run on the same WildFly instance
+
every time a message is consumed by the bridge from the source, it is forward to the target
+
The application client will send a message to the source and consume the "same" message from the target to
+ show that the two destinations were indeed bridged.
+
+
+
JMS Bridge configuration
+
+
The JMS Bridge is configured in the "messaging" subsystem.
+
The Bridge is deployed in the application server when you simply type ./build.sh deploy (or build.bat deploy on windows) (it is copied to ${JBOSS_HOME}/server/default-with-hornetq/deploy/).
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
The example is simple: the application will send a message to the source queue and consume the same message
+ from the target queue.
+
The bridge is configured in the messaging subsystem:
We create and send a message to the source queue. We also display its Message ID.
+
+ TextMessage message = sourceSession.createTextMessage("this is a text message");
+ sourceProducer.send(message);
+ System.out.format("Sent message to %s: %s\n",
+ ((Queue)message.getJMSDestination()).getQueueName(),
+ message.getText());
+ System.out.format("Message ID : %s\n", message.getJMSMessageID());
+
+
+
We close the source connection
+
+ sourceConnection.close();
+
+
+
Now that a message has been sent to the source queue, we will consume a message
+ from the target queue.
+ If the bridge runs correctly, it will have consumed the message from the source and
+ resent it to the target so that we can consume a message from it.
We now display the received message ID. It is not the same than the ID of the message sent to the source queue.
+ The message received from the target queue was sent by the bridge, not by the source message producer
+
+ System.out.format("Message ID : %s\n", messageReceived.getJMSMessageID());
+
+
+
If you need to retrieve the message ID of the message sent to the source, you can use the property HQ_BRIDGE_MSG_ID_LIST
+
+ System.out.format("Bridged Message ID : %s\n", messageReceived.getStringProperty("HQ_BRIDGE_MSG_ID_LIST"));
+
+
+
And finally, always remember to close the JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jms-bridge/server/standalone/configuration/application-roles.properties b/examples/javaee/jms-bridge/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/jms-bridge/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/jms-bridge/server/standalone/configuration/application-users.properties b/examples/javaee/jms-bridge/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/jms-bridge/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/jms-bridge/server/standalone/configuration/logging.properties b/examples/javaee/jms-bridge/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/jms-bridge/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/jms-bridge/server/standalone/configuration/mgmt-users.properties b/examples/javaee/jms-bridge/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/jms-bridge/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/jms-bridge/server/standalone/configuration/standalone-example.xml b/examples/javaee/jms-bridge/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..2850f8cf8a
--- /dev/null
+++ b/examples/javaee/jms-bridge/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,508 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AT_MOST_ONCE
+ 1000
+ 7890
+ 1
+ 1000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jms-bridge/src/main/java/org/hornetq/javaee/example/JMSBridgeExample.java b/examples/javaee/jms-bridge/src/main/java/org/hornetq/javaee/example/JMSBridgeExample.java
new file mode 100644
index 0000000000..89542350b5
--- /dev/null
+++ b/examples/javaee/jms-bridge/src/main/java/org/hornetq/javaee/example/JMSBridgeExample.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * An example which sends a message to a source queue and consume from a target queue.
+ * The source and target queues are bridged by a JMS Bridge configured and running in WildFly.
+ *
+ * @author Jeff Mesnil
+ */
+public class JMSBridgeExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ InitialContext initialContext = null;
+ Connection sourceConnection = null;
+ Connection targetConnection = null;
+ try
+ {
+ // Step 1. Obtain an Initial Context
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Lookup the JMS connection factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/jms/RemoteConnectionFactory");
+
+ // Step 3. Lookup the source queue
+ Queue sourceQueue = (Queue)initialContext.lookup("jms/queues/sourceQueue");
+
+ // Step 4. Create a connection, a session and a message producer for the *source* queue
+ sourceConnection = cf.createConnection("guest", "password");
+ Session sourceSession = sourceConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer sourceProducer = sourceSession.createProducer(sourceQueue);
+
+ // Step 5. Create and send a text message to the *source* queue
+ TextMessage message = sourceSession.createTextMessage("this is a text message");
+ sourceProducer.send(message);
+ System.out.format("Sent message to %s: %s\n",
+ ((Queue)message.getJMSDestination()).getQueueName(),
+ message.getText());
+ System.out.format("Message ID : %s\n", message.getJMSMessageID());
+
+ // Step 6. Close the *source* connection
+ sourceConnection.close();
+
+ // Step 7. Lookup the *target* queue
+ Queue targetQueue = (Queue)initialContext.lookup("jms/queues/targetQueue");
+
+ // Step 8. Create a connection, a session and a message consumer for the *target* queue
+ targetConnection = cf.createConnection("guest", "password");
+ Session targetSession = targetConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer targetConsumer = targetSession.createConsumer(targetQueue);
+
+ // Step 9. Start the connection to receive messages from the *targe* queue
+ targetConnection.start();
+
+ // Step 10. Receive a message from the *target* queue
+ TextMessage messageReceived = (TextMessage)targetConsumer.receive(15000);
+ System.out.format("\nReceived from %s: %s\n",
+ ((Queue)messageReceived.getJMSDestination()).getQueueName(),
+ messageReceived.getText());
+
+ // Step 11. Display the received message's ID
+ System.out.format("Message ID : %s\n", messageReceived.getJMSMessageID());
+
+ // Step 12. Display the message ID of the message received by the *bridge*
+ System.out.format("Bridged Message ID : %s\n", messageReceived.getStringProperty("HQ_BRIDGE_MSG_ID_LIST"));
+ }
+ finally
+ {
+ // Step 13. Be sure to close the resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (sourceConnection != null)
+ {
+ sourceConnection.close();
+ }
+ if (targetConnection != null)
+ {
+ targetConnection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/jms-bridge/src/test/java/org/hornetq/javaee/examples/JMSBridgeRunnerTest.java b/examples/javaee/jms-bridge/src/test/java/org/hornetq/javaee/examples/JMSBridgeRunnerTest.java
new file mode 100644
index 0000000000..3e1b077df3
--- /dev/null
+++ b/examples/javaee/jms-bridge/src/test/java/org/hornetq/javaee/examples/JMSBridgeRunnerTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.JMSBridgeExample;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class JMSBridgeRunnerTest
+{
+ @Test
+ public void runExample() throws Exception
+ {
+ JMSBridgeExample.main(null);
+ }
+}
diff --git a/examples/javaee/jms-bridge/src/test/resources/arquillian.xml b/examples/javaee/jms-bridge/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..1aada30255
--- /dev/null
+++ b/examples/javaee/jms-bridge/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jms-context-injection/pom.xml b/examples/javaee/jms-context-injection/pom.xml
new file mode 100644
index 0000000000..89b6c77aa3
--- /dev/null
+++ b/examples/javaee/jms-context-injection/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-jms-context-example
+ jar
+ HornetQ Java EE MDB JMS Context Example
+
\ No newline at end of file
diff --git a/examples/javaee/jms-context-injection/readme.html b/examples/javaee/jms-context-injection/readme.html
new file mode 100644
index 0000000000..5eaa6da98c
--- /dev/null
+++ b/examples/javaee/jms-context-injection/readme.html
@@ -0,0 +1,108 @@
+
+
+ HornetQ Java EE Injected JMSContext Example
+
+
+
+
+
+
Java EE Injected JMSContext Example
+
+
This example shows you how to inject a JMSContext into an MDB and use it to send a reply to a JMS Client
+
+
Wildfly configuration
+
+
The example leverages the JBoss Arquillian framework to run an Wildfly 8 instance and deploy the MDB.
+
+
Example step-by-step
+
download The latest Wildfly 8 from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
To run the example simply type mvn testfrom the example directory
+
+
+
Firstly in the MDB we inject the JMSContext. This will use the Default Connection Factory configured.
+
We create a JMSContext inside the try-with-resource block so it auto closes
+
+
+ try
+ (
+ // Step 6.Create a JMS Connection inside the try-with-resource block so it will auto close
+ JMSContext context = cf.createContext("guest", "password")
+ )
+
+
+
+
We create a JMS Producer and send a String as a message.
+
+ context.createProducer().send(queue, "This is a text message");
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jms-context-injection/server/standalone/configuration/application-roles.properties b/examples/javaee/jms-context-injection/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/jms-context-injection/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/jms-context-injection/server/standalone/configuration/application-users.properties b/examples/javaee/jms-context-injection/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/jms-context-injection/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/jms-context-injection/server/standalone/configuration/logging.properties b/examples/javaee/jms-context-injection/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/jms-context-injection/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/jms-context-injection/server/standalone/configuration/mgmt-users.properties b/examples/javaee/jms-context-injection/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/jms-context-injection/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/jms-context-injection/server/standalone/configuration/standalone-example.xml b/examples/javaee/jms-context-injection/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..c64af5a547
--- /dev/null
+++ b/examples/javaee/jms-context-injection/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/jms-context-injection/src/main/java/org/hornetq/javaee/example/JmsContextInjectionClientExample.java b/examples/javaee/jms-context-injection/src/main/java/org/hornetq/javaee/example/JmsContextInjectionClientExample.java
new file mode 100644
index 0000000000..ae720b0499
--- /dev/null
+++ b/examples/javaee/jms-context-injection/src/main/java/org/hornetq/javaee/example/JmsContextInjectionClientExample.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSContext;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class JmsContextInjectionClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Thread.sleep(5000);
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 3. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 4. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
+
+ // Step 5. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("jms/RemoteConnectionFactory");
+
+ try
+ (
+ // Step 6.Create a JMS Connection inside the try-with-resource block so it will auto close
+ JMSContext context = cf.createContext("guest", "password")
+ )
+ {
+ // Step 6. create a JMSProducer and send the message
+ context.createProducer().send(queue, "This is a text message");
+
+ // Step 7 start the context
+ context.start();
+
+ // Step 8. look up the reply queue
+ Queue replyQueue = (Queue)initialContext.lookup("jms/queues/replyQueue");
+
+ // Step 9. receive the body of the message as a String
+ String text = context.createConsumer(replyQueue).receiveBody(String.class);
+ }
+ }
+ finally
+ {
+ // Step 10. Be sure to close our Initial Context!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/jms-context-injection/src/main/java/org/hornetq/javaee/example/server/JmsContextInjectionExample.java b/examples/javaee/jms-context-injection/src/main/java/org/hornetq/javaee/example/server/JmsContextInjectionExample.java
new file mode 100644
index 0000000000..83c1a63552
--- /dev/null
+++ b/examples/javaee/jms-context-injection/src/main/java/org/hornetq/javaee/example/server/JmsContextInjectionExample.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.inject.Inject;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import java.util.Calendar;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDB_JMS_CONTEXT",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "consumerMaxRate", propertyValue = "1")
+ })
+public class JmsContextInjectionExample implements MessageListener
+{
+ // 1. Inject the JMSContext
+ @Inject
+ javax.jms.JMSContext context;
+
+ // 2. Map the reply queue
+ @Resource(mappedName = "java:/queue/replyQueue")
+ Queue replyQueue;
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ // Step 10. we print out the message text
+ System.out.println("message " + textMessage.getText() + " received");
+
+ // Step 11. we create a JMSProducer and send a message
+ context.createProducer().send(replyQueue, "this is a reply");
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/jms-context-injection/src/test/java/org/hornetq/javaee/examples/JmsContextInjectionRunnerTest.java b/examples/javaee/jms-context-injection/src/test/java/org/hornetq/javaee/examples/JmsContextInjectionRunnerTest.java
new file mode 100644
index 0000000000..fef539a672
--- /dev/null
+++ b/examples/javaee/jms-context-injection/src/test/java/org/hornetq/javaee/examples/JmsContextInjectionRunnerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.JmsContextInjectionClientExample;
+import org.hornetq.javaee.example.server.JmsContextInjectionExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class JmsContextInjectionRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(JmsContextInjectionExample.class).
+ addAsManifestResource(EmptyAsset.INSTANCE,
+ "beans.xml")
+ .addAsManifestResource(new StringAsset("Dependencies: org.jboss.as.controller-client,org.jboss.dmr,org.jboss.as.cli\n"),
+ "MANIFEST.MF");
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ JmsContextInjectionClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(10000);
+ }
+
+
+}
diff --git a/examples/javaee/jms-context-injection/src/test/resources/arquillian.xml b/examples/javaee/jms-context-injection/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/jms-context-injection/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-bmt/pom.xml b/examples/javaee/mdb-bmt/pom.xml
new file mode 100644
index 0000000000..713744b9a6
--- /dev/null
+++ b/examples/javaee/mdb-bmt/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-bmt-example
+ jar
+ HornetQ Java EE MDB Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-bmt/readme.html b/examples/javaee/mdb-bmt/readme.html
new file mode 100644
index 0000000000..84cd13033b
--- /dev/null
+++ b/examples/javaee/mdb-bmt/readme.html
@@ -0,0 +1,113 @@
+
+
+ HornetQ Java EE MDB Bean Managed Transaction Example
+
+
+
+
+
+
Java EE MDB Bean Managed Transaction Example
+
+
This example shows you how to send a message to an MDB configured to use Bean Managed Transactions
+
The example will send deploy a simple MDB and demonstrate sending a message and the MDB consuming it.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
We create a JMS text messages that we are going to send.
+
+ TextMessage message = session.createTextMessage("This is a text message");
+
+
+
We send messages to the queue
+
+ messageProducer.send(message);
+
+
+
The MDB receives the message
+ We know the message is a TextMessage so we cast to it.
+
+
+ TextMessage tm = (TextMessage)message;
+
+
+
The MDB gets the text and prints it
+
+
+ String text = tm.getText();
+ System.out.println("message " + text + " received");
+
+
+
Now we can do something within a user transaction, let's just start and commit it
+
+
+ UserTransaction tx = ctx.getUserTransaction();
+
+ if(tx != null)
+ {
+ tx.begin();
+ System.out.println("we're in the middle of a transaction: " + tx);
+ tx.commit();
+ }
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
diff --git a/examples/javaee/mdb-bmt/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-bmt/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-bmt/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-bmt/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-bmt/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-bmt/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-bmt/server/standalone/configuration/logging.properties b/examples/javaee/mdb-bmt/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-bmt/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-bmt/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-bmt/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-bmt/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-bmt/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-bmt/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..740cfb6472
--- /dev/null
+++ b/examples/javaee/mdb-bmt/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-bmt/src/main/java/org/hornetq/javaee/example/MDB_BMTClientExample.java b/examples/javaee/mdb-bmt/src/main/java/org/hornetq/javaee/example/MDB_BMTClientExample.java
new file mode 100644
index 0000000000..bf59eea48a
--- /dev/null
+++ b/examples/javaee/mdb-bmt/src/main/java/org/hornetq/javaee/example/MDB_BMTClientExample.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDB_BMTClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/jms/RemoteConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9, 10 and 11 in MDB_BMTExample
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-bmt/src/main/java/org/hornetq/javaee/example/server/MDB_BMTExample.java b/examples/javaee/mdb-bmt/src/main/java/org/hornetq/javaee/example/server/MDB_BMTExample.java
new file mode 100644
index 0000000000..d5661e2c55
--- /dev/null
+++ b/examples/javaee/mdb-bmt/src/main/java/org/hornetq/javaee/example/server/MDB_BMTExample.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.MessageDrivenContext;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import javax.transaction.UserTransaction;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDB_BMTExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Dups-ok-acknowledge")
+ })
+@TransactionManagement(value = TransactionManagementType.BEAN)
+public class MDB_BMTExample implements MessageListener
+{
+ @Resource
+ MessageDrivenContext ctx;
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ // Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text + " received");
+
+ // Step 11. let's look at the user transaction to make sure there isn't one.
+ UserTransaction tx = ctx.getUserTransaction();
+
+ if (tx != null)
+ {
+ tx.begin();
+ System.out.println("we're in the middle of a transaction: " + tx);
+ tx.commit();
+ }
+ else
+ {
+ System.out.println("something is wrong, I wasn't expecting a transaction");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/mdb-bmt/src/test/java/org/hornetq/javaee/example/server/ExampleRunnerTest.java b/examples/javaee/mdb-bmt/src/test/java/org/hornetq/javaee/example/server/ExampleRunnerTest.java
new file mode 100644
index 0000000000..19217978a6
--- /dev/null
+++ b/examples/javaee/mdb-bmt/src/test/java/org/hornetq/javaee/example/server/ExampleRunnerTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.hornetq.javaee.example.MDB_BMTClientExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class ExampleRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDB_BMTExample.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDB_BMTClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(1000);
+ }
+}
diff --git a/examples/javaee/mdb-bmt/src/test/resources/arquillian.xml b/examples/javaee/mdb-bmt/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-bmt/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/pom.xml b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/pom.xml
new file mode 100644
index 0000000000..afdfcc61bf
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-cmt-setrollbackonly-with-dlq-example
+ jar
+ HornetQ Java EE MDB CMT set rollback only with DLQ Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/readme.html b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/readme.html
new file mode 100644
index 0000000000..0fde090083
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/readme.html
@@ -0,0 +1,127 @@
+
+
+ HornetQ Java EE MDB SetRollbackOnly Example
+
+
+
+
+
+
Java EE MDB SetRollbackOnly with DLQ Example
+
+
This example shows you how to send a message to an MDB and then roll back the transaction forcing delivery of the message to a DLQ.
+
The example will send deploy a simple MDB and demonstrate sending a message, MDB consuming it, and then the
+ standalone client consuming it from the DLQ and printing out the special DLQ properties "_HQ_ORIG_ADDRESS"
+ and "_HQ_ORIG_QUEUE".
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/logging.properties b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..b1aa46e545
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,494 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.dlq
+ jms.queue.ExpiryQueue
+ 0
+ 1
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/main/java/org/hornetq/javaee/example/MDB_CMT_SetRollbackOnlyWithDLQClientExample.java b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/main/java/org/hornetq/javaee/example/MDB_CMT_SetRollbackOnlyWithDLQClientExample.java
new file mode 100644
index 0000000000..7b9951bce0
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/main/java/org/hornetq/javaee/example/MDB_CMT_SetRollbackOnlyWithDLQClientExample.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Justin Bertram
+ */
+public class MDB_CMT_SetRollbackOnlyWithDLQClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Perfom a lookup on the destination
+ Destination destination = (Destination) initialContext.lookup("jms/topics/testTopic");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/jms/RemoteConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(destination);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 9, 10, and 11 in MDB_CMT_SetRollbackOnlyWithDLQExample
+
+ // Step 12. Perform a lookup on the DLQ
+ destination = (Destination) initialContext.lookup("jms/queues/dlq");
+
+ // Step 13. Create the consumer and start the connection
+ MessageConsumer consumer = session.createConsumer(destination);
+ connection.start();
+
+ // Step 14. Receive the message.
+ message = (TextMessage) consumer.receive(3000);
+
+ // Step 15. Print the special DLQ properties
+ System.out.println("Original address: " + message.getStringProperty("_HQ_ORIG_ADDRESS"));
+ System.out.println("Original queue: " + message.getStringProperty("_HQ_ORIG_QUEUE"));
+ }
+ finally
+ {
+ // Step 16. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_SetRollbackOnlyWithDLQExample.java b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_SetRollbackOnlyWithDLQExample.java
new file mode 100644
index 0000000000..5b604f47a5
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_SetRollbackOnlyWithDLQExample.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.MessageDrivenContext;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+/**
+ * @author Justin Bertram
+ */
+@MessageDriven(name = "MDB_CMT_SetRollbackOnlyWithDLQExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/testTopic"),
+ @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
+ @ActivationConfigProperty(propertyName = "clientID", propertyValue = "myClientID"),
+ @ActivationConfigProperty(propertyName = "subscriptionName",propertyValue = "mySubscriptionName")
+ })
+public class MDB_CMT_SetRollbackOnlyWithDLQExample implements MessageListener
+{
+ @Resource
+ MessageDrivenContext ctx;
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ // Step 10. get the text from the message.
+ String text = textMessage.getText();
+ System.out.println("message " + text + " received");
+
+ // Step 11. rollback delivery of message to send to DLQ
+ ctx.setRollbackOnly();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/test/java/org/hornetq/javaee/example/MDBCMTSetRollbackOnlyWithDLQRunnerTest.java b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/test/java/org/hornetq/javaee/example/MDBCMTSetRollbackOnlyWithDLQRunnerTest.java
new file mode 100644
index 0000000000..3e45bc4950
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/test/java/org/hornetq/javaee/example/MDBCMTSetRollbackOnlyWithDLQRunnerTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server.MDB_CMT_SetRollbackOnlyWithDLQExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Justin Bertram
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTSetRollbackOnlyWithDLQRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDB_CMT_SetRollbackOnlyWithDLQExample.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDB_CMT_SetRollbackOnlyWithDLQClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(1000);
+ }
+}
diff --git a/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/test/resources/arquillian.xml b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly-with-dlq/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/pom.xml b/examples/javaee/mdb-cmt-setrollbackonly/pom.xml
new file mode 100644
index 0000000000..edfd7f1cb6
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-cmt-setrollbackonly-example
+ jar
+ HornetQ Java EE MDB CMT set rollback only Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/readme.html b/examples/javaee/mdb-cmt-setrollbackonly/readme.html
new file mode 100644
index 0000000000..6b37736ceb
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/readme.html
@@ -0,0 +1,112 @@
+
+
+ HornetQ Java EE MDB SetRollbackOnly Example
+
+
+
+
+
+
Java EE MDB SetRollbackOnly Example
+
+
This example shows you how to send a message to an MDB and then roll back the transaction forcing re delivery
+
The example will send deploy a simple MDB and demonstrate sending a message and the MDB consuming it twice.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
We create a JMS text messages that we are going to send.
+
+ TextMessage message = session.createTextMessage("This is a text message");
+
+
+
We send messages to the queue
+
+ messageProducer.send(message);
+
+
+
The MDB receives the message
+ We know the message is a TextMessage so we cast to it.
+
+
+ TextMessage tm = (TextMessage)message;
+
+
+
The MDB gets the text and prints it, if its the first time we roll back
+
+
+ String text = textMessage.getText();
+
+ if(!textMessage.getJMSRedelivered())
+ {
+ //Step 11. rollback delivery of message if the first time
+ System.out.println("message " + text + " received for the first time");
+ ctx.setRollbackOnly();
+ }
+
+
+
The message is received again but this time we just print the text
+
+
+ System.out.println("message " + text + " received for the second time");
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/logging.properties b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..740cfb6472
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/src/main/java/org/hornetq/javaee/example/MDB_CMT_SetRollbackOnlyClientExample.java b/examples/javaee/mdb-cmt-setrollbackonly/src/main/java/org/hornetq/javaee/example/MDB_CMT_SetRollbackOnlyClientExample.java
new file mode 100644
index 0000000000..8f7fe71a6a
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/src/main/java/org/hornetq/javaee/example/MDB_CMT_SetRollbackOnlyClientExample.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDB_CMT_SetRollbackOnlyClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/jms/RemoteConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9, 10, 11 and 12 in MDB_CMP_SetRollbackOnlyExample
+ }
+ finally
+ {
+ // Step 13. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_SetRollbackOnlyExample.java b/examples/javaee/mdb-cmt-setrollbackonly/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_SetRollbackOnlyExample.java
new file mode 100644
index 0000000000..235a514e30
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_SetRollbackOnlyExample.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.MessageDrivenContext;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDB_CMT_SetRollbackOnlyExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue")
+ })
+public class MDB_CMT_SetRollbackOnlyExample implements MessageListener
+{
+ @Resource
+ MessageDrivenContext ctx;
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ // Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ if (!textMessage.getJMSRedelivered())
+ {
+ // Step 11. rollback delivery of message if the first time
+ System.out.println("message " + text + " received for the first time");
+ ctx.setRollbackOnly();
+ }
+ else
+ {
+ // Step 12. read the message
+ System.out.println("message " + text + " received for the second time");
+ }
+
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/src/test/java/org/hornetq/javaee/example/MDBCMTSetRollbackOnlyRunnerTest.java b/examples/javaee/mdb-cmt-setrollbackonly/src/test/java/org/hornetq/javaee/example/MDBCMTSetRollbackOnlyRunnerTest.java
new file mode 100644
index 0000000000..58d693d716
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/src/test/java/org/hornetq/javaee/example/MDBCMTSetRollbackOnlyRunnerTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server.MDB_CMT_SetRollbackOnlyExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTSetRollbackOnlyRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDB_CMT_SetRollbackOnlyExample.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDB_CMT_SetRollbackOnlyClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(1000);
+ }
+}
diff --git a/examples/javaee/mdb-cmt-setrollbackonly/src/test/resources/arquillian.xml b/examples/javaee/mdb-cmt-setrollbackonly/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-cmt-setrollbackonly/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-local/pom.xml b/examples/javaee/mdb-cmt-tx-local/pom.xml
new file mode 100644
index 0000000000..9dcfb0ac30
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-cmt-tx-local-example
+ jar
+ HornetQ Java EE MDB CMT Local Transaction Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-local/readme.html b/examples/javaee/mdb-cmt-tx-local/readme.html
new file mode 100644
index 0000000000..350864d6c5
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/readme.html
@@ -0,0 +1,125 @@
+
+
+ HornetQ Java EE MDB using a local transaction Example
+
+
+
+
+
+
Java EE MDB using a local transaction Example
+
+
This example shows you how to send a message to an MDB and deliver it within a local transaction
+
The example will send deploy a simple MDB and demonstrate sending a message and the MDB consuming it, throwing an exception and the message being re delivered.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
We create a JMS text messages that we are going to send.
+
+ TextMessage message = session.createTextMessage("This is a text message");
+
+
+
We send messages to the queue
+
+ messageProducer.send(message);
+
+
+
The MDB receives the message
+ We know the message is a TextMessage so we cast to it.
+
+
+ TextMessage tm = (TextMessage)message;
+
+
+
The MDB gets the text and prints it, we take a quick look at the transaction and throw an exception.
+
+
+ System.out.println("message " + text + " received");
+
+ if (!textMessage.getJMSRedelivered())
+ {
+ //Step 11. On first delivery get the transaction, take a look, and throw an exception
+ Transaction tx = tm.getTransaction();
+
+ if (tx != null)
+ {
+ System.out.println("something is wrong, there should be no global transaction: " + tx);
+ }
+ else
+ {
+ System.out.println("there is no global transaction, although the message delivery is using a local transaction");
+ System.out.println("let's throw an exception and see what happens");
+ throw new RuntimeException("DOH!");
+ }
+ }
+
+
+
The MDB receives the message again and we print a message.
+
+
+ System.out.println("The message was redelivered since the message delivery used a local transaction");
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/logging.properties b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..740cfb6472
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-cmt-tx-local/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxLocalClientExample.java b/examples/javaee/mdb-cmt-tx-local/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxLocalClientExample.java
new file mode 100644
index 0000000000..68162e6d1d
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxLocalClientExample.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDB_CMT_TxLocalClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/jms/RemoteConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9,,10, 11 and 12 in MDB_CMP_TxLocalExample
+ }
+ finally
+ {
+ // Step 13. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-local/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxLocalExample.java b/examples/javaee/mdb-cmt-tx-local/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxLocalExample.java
new file mode 100644
index 0000000000..d0786a6b71
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxLocalExample.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDB_CMT_TxLocalExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "useLocalTx", propertyValue = "true")
+ })
+@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
+public class MDB_CMT_TxLocalExample implements MessageListener
+{
+ @Resource(mappedName = "java:/TransactionManager")
+ private TransactionManager tm;
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ // Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text + " received");
+
+ if (!textMessage.getJMSRedelivered())
+ {
+ // Step 11. On first delivery get the transaction, take a look, and throw an exception
+ Transaction tx = tm.getTransaction();
+
+ if (tx != null)
+ {
+ System.out.println("something is wrong, there should be no global transaction: " + tx);
+ }
+ else
+ {
+ System.out.println("there is no global transaction, although the message delivery is using a local transaction");
+ System.out.println("let's throw an exception and see what happens");
+ throw new RuntimeException("DOH!");
+ }
+ }
+ else
+ {
+ // Step 12. Print the message
+ System.out.println("The message was redelivered since the message delivery used a local transaction");
+ }
+
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ catch (SystemException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/mdb-cmt-tx-local/src/test/java/org/hornetq/javaee/example/MDBCMTSetLocalTXRunnerTest.java b/examples/javaee/mdb-cmt-tx-local/src/test/java/org/hornetq/javaee/example/MDBCMTSetLocalTXRunnerTest.java
new file mode 100644
index 0000000000..18fee164a3
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/src/test/java/org/hornetq/javaee/example/MDBCMTSetLocalTXRunnerTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server.MDB_CMT_TxLocalExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTSetLocalTXRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDB_CMT_TxLocalExample.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDB_CMT_TxLocalClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(1000);
+ }
+}
diff --git a/examples/javaee/mdb-cmt-tx-local/src/test/resources/arquillian.xml b/examples/javaee/mdb-cmt-tx-local/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-local/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/pom.xml b/examples/javaee/mdb-cmt-tx-not-supported/pom.xml
new file mode 100644
index 0000000000..ead5118878
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-cmt-no-tx-example
+ jar
+ HornetQ Java EE MDB CMT Transaction Not Supported Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/readme.html b/examples/javaee/mdb-cmt-tx-not-supported/readme.html
new file mode 100644
index 0000000000..fe43ff2c3a
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/readme.html
@@ -0,0 +1,116 @@
+
+
+ HornetQ Java EE MDB Container Managed Transaction with NOT_SUPPORTED transaction Example
+
+
+
+
+
+
Java EE MDB Container Managed Transaction with NOT_SUPPORTED transaction Example
+
+
This example shows you how to send a message to an MDB
+
The example will deploy a simple MDB and send a message. The MDB consuming it will not use a transaction.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
We create a JMS text messages that we are going to send.
+
+ TextMessage message = session.createTextMessage("This is a text message");
+
+
+
We send messages to the queue
+
+ messageProducer.send(message);
+
+
+
The MDB receives the message
+ We know the message is a TextMessage so we cast to it.
+
+
+ TextMessage tm = (TextMessage)message;
+
+
+
The MDB gets the text and prints it
+
+
+ String text = tm.getText();
+ System.out.println("message " + text + " received");
+
+
+
+
We look at the transaction to make sure there isn't one
+
+
+ Transaction tx = tm.getTransaction();
+
+ if(tx == null)
+ {
+ System.out.println("tx is null, just as expected");
+ }
+
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/logging.properties b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..740cfb6472
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxNotSupportedClientExample.java b/examples/javaee/mdb-cmt-tx-not-supported/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxNotSupportedClientExample.java
new file mode 100644
index 0000000000..1c39ac887f
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxNotSupportedClientExample.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDB_CMT_TxNotSupportedClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+ initialContext = new InitialContext(env);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("jms/RemoteConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9,10 and 11 in MDB_CMP_TxNotSupported
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxNotSupported.java b/examples/javaee/mdb-cmt-tx-not-supported/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxNotSupported.java
new file mode 100644
index 0000000000..3763a75467
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxNotSupported.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDB_CMT_TxNotSupported",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")
+ })
+@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
+public class MDB_CMT_TxNotSupported implements MessageListener
+{
+ @Resource(mappedName = "java:/TransactionManager")
+ private TransactionManager tm;
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ // Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text + " received");
+
+ // Step 11. let's look at the transaction to make sure there isn't one.
+ Transaction tx = tm.getTransaction();
+
+ if (tx == null)
+ {
+ System.out.println("tx is null, just as expected");
+ }
+ else
+ {
+ System.out.println("something is wrong, I wasn't expecting a transaction");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/src/test/java/org/hornetq/javaee/example/MDBCMTSetTXNotSupportedRunnerTest.java b/examples/javaee/mdb-cmt-tx-not-supported/src/test/java/org/hornetq/javaee/example/MDBCMTSetTXNotSupportedRunnerTest.java
new file mode 100644
index 0000000000..4e5328614f
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/src/test/java/org/hornetq/javaee/example/MDBCMTSetTXNotSupportedRunnerTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server.MDB_CMT_TxNotSupported;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTSetTXNotSupportedRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDB_CMT_TxNotSupported.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDB_CMT_TxNotSupportedClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(1000);
+ }
+}
diff --git a/examples/javaee/mdb-cmt-tx-not-supported/src/test/resources/arquillian.xml b/examples/javaee/mdb-cmt-tx-not-supported/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-not-supported/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-required/pom.xml b/examples/javaee/mdb-cmt-tx-required/pom.xml
new file mode 100644
index 0000000000..739e4d0aa4
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-cmt-tx-example
+ jar
+ HornetQ Java EE MDB CMT Transaction Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-required/readme.html b/examples/javaee/mdb-cmt-tx-required/readme.html
new file mode 100644
index 0000000000..8ecd05fa7a
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/readme.html
@@ -0,0 +1,115 @@
+
+
+ HornetQ Java EE MDB Container Managed Transactions Example
+
+
+
+
+
+
Java EE MDB Container Managed Transactions Example
+
+
This example shows you how to send a message to an MDB that is delivered within a transaction controlled by the container
+
The example will send deploy a simple MDB and demonstrate sending a message and the MDB consuming it
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
We create a JMS text messages that we are going to send.
+
+ TextMessage message = session.createTextMessage("This is a text message");
+
+
+
We send messages to the queue
+
+ messageProducer.send(message);
+
+
+
The MDB receives the message
+ We know the message is a TextMessage so we cast to it.
+
+
+ TextMessage tm = (TextMessage)message;
+
+
+
We take alook at the transaction and see that it is running.
+
+
+ Transaction tx = tm.getTransaction();
+
+ if(tx != null)
+ {
+ System.out.println("we're in the middle of a transaction: " + tx);
+ }
+
+
+
The MDB gets the text and prints it
+
+
+ String text = tm.getText();
+ System.out.println("message " + text + " received");
+
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/logging.properties b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..c3203b9ea6
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-cmt-tx-required/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxRequiredClientExample.java b/examples/javaee/mdb-cmt-tx-required/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxRequiredClientExample.java
new file mode 100644
index 0000000000..1e9dc44fc3
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/src/main/java/org/hornetq/javaee/example/MDB_CMT_TxRequiredClientExample.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDB_CMT_TxRequiredClientExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ Thread.sleep(5000);
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("jms/RemoteConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+ TextMessage message = null;
+
+ for (int i = 0; i < 100; i++)
+ {
+ // Step 7. Create a Text Message
+ message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+ // Step 8. Send the Message
+ producer.send(message);
+ }
+
+
+ // Step 9,10 and 11 in MDBExample
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/mdb-cmt-tx-required/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxRequiredExample.java b/examples/javaee/mdb-cmt-tx-required/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxRequiredExample.java
new file mode 100644
index 0000000000..0520bd5b6a
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/src/main/java/org/hornetq/javaee/example/server/MDB_CMT_TxRequiredExample.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import java.util.Calendar;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDB_CMT_TxRequiredExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "consumerMaxRate", propertyValue = "1")
+ })
+public class MDB_CMT_TxRequiredExample implements MessageListener
+{
+
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ // Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage) message;
+
+ // Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ Calendar c = Calendar.getInstance();
+
+ System.out.println("message " + text + " received at " + c.getTime());
+
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/examples/javaee/mdb-cmt-tx-required/src/test/java/org/hornetq/javaee/examples/MDBCMTSetTXRequiredRunnerTest.java b/examples/javaee/mdb-cmt-tx-required/src/test/java/org/hornetq/javaee/examples/MDBCMTSetTXRequiredRunnerTest.java
new file mode 100644
index 0000000000..e2696182fb
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/src/test/java/org/hornetq/javaee/examples/MDBCMTSetTXRequiredRunnerTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.MDB_CMT_TxRequiredClientExample;
+import org.hornetq.javaee.example.server.MDB_CMT_TxRequiredExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTSetTXRequiredRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDB_CMT_TxRequiredExample.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDB_CMT_TxRequiredClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(10000);
+ }
+
+
+}
diff --git a/examples/javaee/mdb-cmt-tx-required/src/test/resources/arquillian.xml b/examples/javaee/mdb-cmt-tx-required/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-cmt-tx-required/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-message-selector/pom.xml b/examples/javaee/mdb-message-selector/pom.xml
new file mode 100644
index 0000000000..64363c4fbb
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-message-selector-example
+ jar
+ HornetQ Java EE MDB Message Selector Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-message-selector/readme.html b/examples/javaee/mdb-message-selector/readme.html
new file mode 100644
index 0000000000..e5f02d5296
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/readme.html
@@ -0,0 +1,127 @@
+
+
+ HornetQ Java EE MDB Message Selector Example
+
+
+
+
+
+
Java EE MDB Message Selector Example
+
+
This example shows you how to send a message to an MDB that is configured to use a message selector
+
The example will send deploy a simple MDB and demonstrate sending a message and the MDB consuming only the message that matches the message selector.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
We create a second JMS text message that we are going to send.
+
+ TextMessage redMessage = session.createTextMessage("This is a text message");
+
+
+
Set the color property on the message to 'RED'.
+
+ redMessage.setStringProperty("color", "RED");
+
+
+
We send messages to the queue
+
+ messageProducer.send(redMessage);
+
+
+
The MDB receives the message
+ We know the message is a TextMessage so we cast to it.
+
+
+ TextMessage tm = (TextMessage)message;
+
+
+
We get the color property to check it
+
+
+ String color = textMessage.getStringProperty("color");
+
+
+
The MDB gets the text and color and print it
+
+
+ String text = tm.getText();
+ System.out.println("message " + text + " received color=" + color);
+
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-message-selector/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-message-selector/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-message-selector/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-message-selector/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-message-selector/server/standalone/configuration/logging.properties b/examples/javaee/mdb-message-selector/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-message-selector/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-message-selector/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-message-selector/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-message-selector/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..c3203b9ea6
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-message-selector/src/main/java/org/hornetq/javaee/example/MDBMessageSelectorClientExample.java b/examples/javaee/mdb-message-selector/src/main/java/org/hornetq/javaee/example/MDBMessageSelectorClientExample.java
new file mode 100644
index 0000000000..45da301aed
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/src/main/java/org/hornetq/javaee/example/MDBMessageSelectorClientExample.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDBMessageSelectorClientExample
+{
+ public static void main(String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ //Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ //Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("jms/queues/testQueue");
+
+ //Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ //Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ //Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ //Step 7. Create a Text Message and set the color property to blue
+ TextMessage blueMessage = session.createTextMessage("This is a text message");
+
+ blueMessage.setStringProperty("color", "BLUE");
+
+ System.out.println("Sent message: " + blueMessage.getText() + " color=BLUE");
+
+ //Step 8. Send the Message
+ producer.send(blueMessage);
+
+ //Step 9. create another message and set the color property to red
+ TextMessage redMessage = session.createTextMessage("This is a text message");
+
+ redMessage.setStringProperty("color", "RED");
+
+ System.out.println("Sent message: " + redMessage.getText() + " color=RED");
+
+ //Step 10. Send the Message
+ producer.send(redMessage);
+ //Step 10,11 and 12 in MDBMessageSelectorExample
+ }
+ finally
+ {
+ //Step 13. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if(connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-message-selector/src/main/java/org/hornetq/javaee/example/server/MDBMessageSelectorExample.java b/examples/javaee/mdb-message-selector/src/main/java/org/hornetq/javaee/example/server/MDBMessageSelectorExample.java
new file mode 100644
index 0000000000..92d8c2942c
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/src/main/java/org/hornetq/javaee/example/server/MDBMessageSelectorExample.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDBMessageSelectorExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
+ @ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "color = 'RED'")
+ })
+public class MDBMessageSelectorExample implements MessageListener
+{
+ public void onMessage(Message message)
+ {
+ try
+ {
+ //Step 11. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ //Step 12. get the text from the message.
+ String text = textMessage.getText();
+
+ //Step 13. We check we received the right color of message
+ String color = textMessage.getStringProperty("color");
+
+ System.out.println("message " + text + " received color=" + color);
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-message-selector/src/test/java/org/hornetq/javaee/examples/MDBCMTSetMessageSelectorRunnerTest.java b/examples/javaee/mdb-message-selector/src/test/java/org/hornetq/javaee/examples/MDBCMTSetMessageSelectorRunnerTest.java
new file mode 100644
index 0000000000..2f821cfdfc
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/src/test/java/org/hornetq/javaee/examples/MDBCMTSetMessageSelectorRunnerTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.MDBMessageSelectorClientExample;
+import org.hornetq.javaee.example.server.MDBMessageSelectorExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTSetMessageSelectorRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDBMessageSelectorExample.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDBMessageSelectorClientExample.main(null);
+ //give the example time to run
+ Thread.sleep(1000);
+ }
+}
diff --git a/examples/javaee/mdb-message-selector/src/test/resources/arquillian.xml b/examples/javaee/mdb-message-selector/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-message-selector/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover-static/pom.xml b/examples/javaee/mdb-remote-failover-static/pom.xml
new file mode 100644
index 0000000000..b2f0d49406
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/pom.xml
@@ -0,0 +1,90 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-remote-failover-static-example
+ jar
+ HornetQ Java EE MDB Remote Failover Static Example
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ as-node1
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node1
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+ as-node2
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node2
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12
+
+ -Dlogging.configuration=file:///${user.dir}/test/config/logging.properties
+
+
+ clustering-all
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover-static/readme.html b/examples/javaee/mdb-remote-failover-static/readme.html
new file mode 100644
index 0000000000..cff2f46aab
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/readme.html
@@ -0,0 +1,165 @@
+
+
+ HornetQ Java EE MDB Message Selector Example
+
+
+
+
+
+
Java EE MDB Remote Failover Static Example
+
+
This example shows you how to send a message to an MDB that is configured to consume from a live/backup pair.
+
The example will send deploy a simple MDB to one Wildfly instance. Then it will send a message to the live server of the live/backup pair
+ which will be consumed by the MDB after which the MDB will send a reply message which will be consumed by the example program. Then the live
+ server will be stopped so that the backup takes over and the process will be repeated.
+
+
Unlike the "Java EE MDB Remote Failover Example," this example uses a "static" configuration for finding all the nodes. In other words
+ it doesn't use UDP multicast for server discovery.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/logging.properties b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..309305ab16
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=ffd6e94a09c5a9ea5e216737dd45b99d
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-backup.xml b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-backup.xml
new file mode 100644
index 0000000000..2045cee270
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-backup.xml
@@ -0,0 +1,511 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+ jms
+ http-connector
+
+ remote-http
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..49aa8f5247
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,508 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ guest
+ password
+ true
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-live.xml b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-live.xml
new file mode 100644
index 0000000000..bd258131cd
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/server/standalone/configuration/standalone-live.xml
@@ -0,0 +1,513 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+ jms
+ http-connector
+
+ remote-http
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/MDBRemoteFailoverStaticClientExample.java b/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/MDBRemoteFailoverStaticClientExample.java
new file mode 100644
index 0000000000..5106dd7ffc
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/MDBRemoteFailoverStaticClientExample.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server.ServerKiller;
+
+import javax.jms.*;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+public class MDBRemoteFailoverStaticClientExample
+{
+ private static ServerKiller killer;
+
+ public static void main(String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ //Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8180");
+
+ env.put(Context.SECURITY_PRINCIPAL, "guest");
+
+ env.put(Context.SECURITY_CREDENTIALS, "password");
+
+ initialContext = new InitialContext(env);
+
+ //Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("/queues/inQueue");
+
+ //Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ //Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ //Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ //Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ //Step 8. Send the Message
+ producer.send(message);
+
+ //Step 15. We lookup the reply queue
+ queue = (Queue) initialContext.lookup("/queues/outQueue");
+
+ //Step 16. We create a JMS message consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ //Step 17. We start the connedction so we can receive messages
+ connection.start();
+
+ //Step 18. We receive the message and print it out
+ message = (TextMessage) messageConsumer.receive(5000);
+
+ System.out.println("message.getText() = " + message.getText());
+
+ System.out.println("Killing Live Server");
+
+ killer.kill();
+
+ //Step 7. Create a Text Message
+ message = session.createTextMessage("This is another text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ //Step 8. Send the Message
+ producer.send(message);
+
+ //Step 18. We receive the message and print it out
+ message = (TextMessage) messageConsumer.receive(5000);
+
+ System.out.println("message.getText() = " + message.getText());
+
+ }
+ finally
+ {
+ //Step 19. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if(connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+ public static void setKiller(ServerKiller killer)
+ {
+ MDBRemoteFailoverStaticClientExample.killer = killer;
+ }
+
+}
diff --git a/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/server/MDBRemoteFailoverStaticExample.java b/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/server/MDBRemoteFailoverStaticExample.java
new file mode 100644
index 0000000000..f5cacee031
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/server/MDBRemoteFailoverStaticExample.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.hornetq.api.jms.HornetQJMSClient;
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import javax.annotation.Resource;
+import javax.ejb.*;
+import javax.jms.*;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@MessageDriven(name = "MDBRemoteFailoverStaticExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "inQueue"),
+ @ActivationConfigProperty(propertyName = "hA", propertyValue = "true"),
+ @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false")
+ })
+@ResourceAdapter("hornetq-remote-ra.rar")
+public class MDBRemoteFailoverStaticExample implements MessageListener
+{
+ @Resource(mappedName = "java:/RemoteJmsXA")
+ ConnectionFactory connectionFactory;
+ Queue replyQueue;
+
+ public void onMessage(Message message)
+ {
+ Connection conn = null;
+ try
+ {
+ replyQueue = HornetQJMSClient.createQueue("outQueue");
+ //Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ //Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text);
+
+ //Step 11. we create a JMS connection
+ conn = connectionFactory.createConnection("guest", "password");
+
+ //Step 12. We create a JMS session
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 13. we create a producer for the reply queue
+ MessageProducer producer = sess.createProducer(replyQueue);
+
+ //Step 14. we create a message and send it
+ producer.send(sess.createTextMessage("this is a reply"));
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (JMSException e)
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/server/ServerKiller.java b/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/server/ServerKiller.java
new file mode 100644
index 0000000000..f9d568f4a3
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/src/main/java/org/hornetq/javaee/example/server/ServerKiller.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+/**
+ * @author Andy Taylor
+ * Date: 12/06/12
+ */
+public interface ServerKiller
+{
+ void kill();
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover-static/src/test/java/org/hornetq/javaee/examples/FailoverStaticRunnerTest.java b/examples/javaee/mdb-remote-failover-static/src/test/java/org/hornetq/javaee/examples/FailoverStaticRunnerTest.java
new file mode 100644
index 0000000000..496bc04db4
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/src/test/java/org/hornetq/javaee/examples/FailoverStaticRunnerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.MDBRemoteFailoverStaticClientExample;
+import org.hornetq.javaee.example.server.MDBRemoteFailoverStaticExample;
+import org.hornetq.javaee.example.server.ServerKiller;
+import org.jboss.arquillian.container.test.api.ContainerController;
+import org.jboss.arquillian.container.test.api.Deployer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.junit.InSequence;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * 5/21/12
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class FailoverStaticRunnerTest
+{
+ @ArquillianResource
+ private ContainerController controller;
+ @ArquillianResource
+ private Deployer deployer;
+
+ @Deployment(name = "deploy-0", managed = false)
+ @TargetsContainer("node-0")
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDBRemoteFailoverStaticExample.class);
+
+ final WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war");
+ war.addAsManifestResource("jboss-deployment-structure.xml", "jboss-deployment-structure.xml");
+ war.addAsLibrary(ejbJar);
+ System.out.println(war.toString(true));
+ return war;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDBRemoteFailoverStaticClientExample.setKiller(new ServerKiller()
+ {
+ @Override
+ public void kill()
+ {
+ controller.kill("node-1");
+ }
+ });
+
+ MDBRemoteFailoverStaticClientExample.main(null);
+ }
+
+ @Test
+ @InSequence(-1)
+ public void startServer()
+ {
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-1");
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-2");
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-0");
+ System.out.println("*****************************************************************************************************************************************************************");
+ deployer.deploy("deploy-0");
+ }
+
+ @Test
+ @InSequence(1)
+ public void stopServer()
+ {
+ deployer.undeploy("deploy-0");
+ controller.stop("node-0");
+ controller.stop("node-2");
+ }
+}
diff --git a/examples/javaee/mdb-remote-failover-static/src/test/resources/arquillian.xml b/examples/javaee/mdb-remote-failover-static/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..d457ec74a6
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/src/test/resources/arquillian.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ -Djboss.node.name=node-0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+ ${basedir}/target/jbossas-node1
+ -Djboss.node.name=node-1 -Djboss.socket.binding.port-offset=100
+ standalone-live.xml
+ true
+ ${node0:127.0.0.1}
+ ${as.managementPort:10090}
+
+
+
+
+ ${basedir}/target/jbossas-node2
+ -Djboss.node.name=node-2 -Djboss.socket.binding.port-offset=200
+ standalone-backup.xml
+ true
+ ${node0:127.0.0.1}
+ ${as.managementPort:10190}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover-static/src/test/resources/jboss-deployment-structure.xml b/examples/javaee/mdb-remote-failover-static/src/test/resources/jboss-deployment-structure.xml
new file mode 100644
index 0000000000..5bd26f867f
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover-static/src/test/resources/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover/pom.xml b/examples/javaee/mdb-remote-failover/pom.xml
new file mode 100644
index 0000000000..2187ee287f
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/pom.xml
@@ -0,0 +1,90 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-remote-failover-example
+ jar
+ HornetQ Java EE MDB Remote Failover Example
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ as-node1
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node1
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+ as-node2
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node2
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12
+
+ -Dlogging.configuration=file:///${user.dir}/test/config/logging.properties
+
+
+ clustering-all
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover/readme.html b/examples/javaee/mdb-remote-failover/readme.html
new file mode 100644
index 0000000000..836b8eb9d6
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/readme.html
@@ -0,0 +1,165 @@
+
+
+ HornetQ Java EE MDB Message Selector Example
+
+
+
+
+
+
Java EE MDB Remote Failover Example
+
+
This example shows you how to send a message to an MDB that is configured to consume from a live/backup pair.
+
The example will send deploy a simple MDB to one Wildfly instance. Then it will send a message to the live server of the live/backup pair
+ which will be consumed by the MDB after which the MDB will send a reply message which will be consumed by the example program. Then the live
+ server will be stopped so that the backup takes over and the process will be repeated.
+
+
Unlike the "Java EE MDB Remote Failover Static Example," this example uses a "dynamic" configuration for finding all the nodes. In other words
+ it uses UDP multicast for server discovery.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-remote-failover/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-remote-failover/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/logging.properties b/examples/javaee/mdb-remote-failover/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-remote-failover/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..309305ab16
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=ffd6e94a09c5a9ea5e216737dd45b99d
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-backup.xml b/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-backup.xml
new file mode 100644
index 0000000000..15aa305e45
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-backup.xml
@@ -0,0 +1,519 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+ messaging-group
+ 5000
+ http-connector
+
+
+
+
+ messaging-group
+ 10000
+
+
+
+
+ jms
+ http-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..e9242484b2
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,504 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ messaging-group
+ 10000
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ guest
+ password
+ true
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-live.xml b/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-live.xml
new file mode 100644
index 0000000000..a5e67a3c94
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/server/standalone/configuration/standalone-live.xml
@@ -0,0 +1,521 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+ messaging-group
+ 5000
+ http-connector
+
+
+
+
+ messaging-group
+ 10000
+
+
+
+
+ jms
+ http-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/MDBRemoteFailoverClientExample.java b/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/MDBRemoteFailoverClientExample.java
new file mode 100644
index 0000000000..1fb5683784
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/MDBRemoteFailoverClientExample.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import org.hornetq.javaee.example.server.ServerKiller;
+
+import javax.jms.*;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+public class MDBRemoteFailoverClientExample
+{
+ private static ServerKiller killer;
+
+ public static void main(String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ //Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8180");
+
+ initialContext = new InitialContext(env);
+ //Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("/queues/inQueue");
+
+ //Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ //Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ //Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ //Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ //Step 8. Send the Message
+ producer.send(message);
+
+ //Step 15. We lookup the reply queue
+ queue = (Queue) initialContext.lookup("/queues/outQueue");
+
+ //Step 16. We create a JMS message consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ //Step 17. We start the connection so we can receive messages
+ connection.start();
+
+ //Step 18. We receive the message and print it out
+ message = (TextMessage) messageConsumer.receive(20000);
+
+ System.out.println("message.getText() = " + message.getText());
+
+ //Step 19. Kill the live server
+ System.out.println("Killing Live Server");
+ killer.kill();
+
+ //Step 20. Create a Text Message
+ message = session.createTextMessage("This is another text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ //Step 21. Send the Message
+ producer.send(message);
+
+ //Step 22. We receive the message and print it out
+ message = (TextMessage) messageConsumer.receive(20000);
+
+ System.out.println("message.getText() = " + message.getText());
+ }
+ finally
+ {
+ //Step 23. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if(connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+ public static void setKiller(ServerKiller killer)
+ {
+ MDBRemoteFailoverClientExample.killer = killer;
+ }
+}
diff --git a/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/server/MDBRemoteFailoverExample.java b/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/server/MDBRemoteFailoverExample.java
new file mode 100644
index 0000000000..e6c15e0692
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/server/MDBRemoteFailoverExample.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.hornetq.api.jms.HornetQJMSClient;
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.*;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@MessageDriven(name = "MDBRemoteFailoverExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "inQueue"),
+ @ActivationConfigProperty(propertyName = "hA", propertyValue = "true"),
+ @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false")
+ })
+@ResourceAdapter("hornetq-remote-ra.rar")
+public class MDBRemoteFailoverExample implements MessageListener
+{
+
+ @Resource(mappedName = "java:/RemoteJmsXA")
+ ConnectionFactory connectionFactory;
+ Queue replyQueue;
+
+ public void onMessage(Message message)
+ {
+ Connection conn = null;
+ try
+ {
+ replyQueue = HornetQJMSClient.createQueue("outQueue");
+ //Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ //Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text);
+
+ //Step 11. we create a JMS connection
+ conn = connectionFactory.createConnection();
+
+ //Step 12. We create a JMS session
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 13. we create a producer for the reply queue
+ MessageProducer producer = sess.createProducer(replyQueue);
+
+ //Step 14. we create a message and send it
+ producer.send(sess.createTextMessage("this is a reply"));
+
+ System.out.println("reply sent");
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (JMSException e)
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/server/ServerKiller.java b/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/server/ServerKiller.java
new file mode 100644
index 0000000000..f5494f7114
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/src/main/java/org/hornetq/javaee/example/server/ServerKiller.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+/**
+ * @author Andy Taylor
+ * Date: 12/06/12
+ */
+public interface ServerKiller
+{
+ void kill();
+}
diff --git a/examples/javaee/mdb-remote-failover/src/test/java/org/hornetq/javaee/examples/FailoverRunnerTest.java b/examples/javaee/mdb-remote-failover/src/test/java/org/hornetq/javaee/examples/FailoverRunnerTest.java
new file mode 100644
index 0000000000..0838fd0df0
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/src/test/java/org/hornetq/javaee/examples/FailoverRunnerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.MDBRemoteFailoverClientExample;
+import org.hornetq.javaee.example.server.MDBRemoteFailoverExample;
+import org.hornetq.javaee.example.server.ServerKiller;
+import org.jboss.arquillian.container.test.api.*;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.junit.InSequence;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class FailoverRunnerTest
+{
+ @ArquillianResource
+ private ContainerController controller;
+ @ArquillianResource
+ private Deployer deployer;
+
+ @Deployment(name = "deploy-0", managed = false)
+ @TargetsContainer("node-0")
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDBRemoteFailoverExample.class);
+
+ final WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war");
+ war.addAsManifestResource("jboss-deployment-structure.xml", "jboss-deployment-structure.xml");
+ war.addAsLibrary(ejbJar);
+ System.out.println(war.toString(true));
+ return war;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDBRemoteFailoverClientExample.setKiller(new ServerKiller()
+ {
+ @Override
+ public void kill()
+ {
+ controller.kill("node-1");
+ }
+ });
+
+ MDBRemoteFailoverClientExample.main(null);
+ }
+
+ @Test
+ @InSequence(-1)
+ public void startServer()
+ {
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-1");
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-2");
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("node-0");
+ System.out.println("*****************************************************************************************************************************************************************");
+ deployer.deploy("deploy-0");
+ }
+
+ @Test
+ @InSequence(1)
+ public void stopServer()
+ {
+ deployer.undeploy("deploy-0");
+ controller.stop("node-0");
+ controller.stop("node-2");
+ }
+
+}
diff --git a/examples/javaee/mdb-remote-failover/src/test/resources/arquillian.xml b/examples/javaee/mdb-remote-failover/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..c6a1ebbc50
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/src/test/resources/arquillian.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ -Djboss.node.name=node-0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+ ${basedir}/target/jbossas-node1
+ -Djboss.node.name=node-1 -Djboss.socket.binding.port-offset=100
+ standalone-live.xml
+ true
+ ${node0:127.0.0.1}
+ ${as.managementPort:10090}
+
+
+
+
+ ${basedir}/target/jbossas-node2
+ -Djboss.node.name=node-2 -Djboss.socket.binding.port-offset=200
+ standalone-backup.xml
+ true
+ ${node0:127.0.0.1}
+ ${as.managementPort:10190}
+
+
+
+
+
+
+
+
diff --git a/examples/javaee/mdb-remote-failover/src/test/resources/jboss-deployment-structure.xml b/examples/javaee/mdb-remote-failover/src/test/resources/jboss-deployment-structure.xml
new file mode 100644
index 0000000000..5bd26f867f
--- /dev/null
+++ b/examples/javaee/mdb-remote-failover/src/test/resources/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/pom.xml b/examples/javaee/mdb-tx-send/pom.xml
new file mode 100644
index 0000000000..11ed2e4e9e
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-mdb-tx-send-example
+ jar
+ HornetQ Java EE MDB Transactional Send Example
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/readme.html b/examples/javaee/mdb-tx-send/readme.html
new file mode 100644
index 0000000000..ef72d1756f
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/readme.html
@@ -0,0 +1,155 @@
+
+
+ HornetQ Java EE MDB Send Example
+
+
+
+
+
+
Java EE MDB TX Send Example
+
+
This example shows you how to send a message to an MDB that returns a reply using the same XA transaction.
+
The example will send deploy a simple MDB and demonstrate sending a message and the MDB consuming it.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
+
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/server/standalone/configuration/application-roles.properties b/examples/javaee/mdb-tx-send/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/mdb-tx-send/server/standalone/configuration/application-users.properties b/examples/javaee/mdb-tx-send/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/mdb-tx-send/server/standalone/configuration/logging.properties b/examples/javaee/mdb-tx-send/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/mdb-tx-send/server/standalone/configuration/mgmt-users.properties b/examples/javaee/mdb-tx-send/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/mdb-tx-send/server/standalone/configuration/standalone-example.xml b/examples/javaee/mdb-tx-send/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..ca446061db
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/src/main/java/org/hornetq/javaee/example/MDBMessageSendTxClientExample.java b/examples/javaee/mdb-tx-send/src/main/java/org/hornetq/javaee/example/MDBMessageSendTxClientExample.java
new file mode 100644
index 0000000000..4d4d938db8
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/src/main/java/org/hornetq/javaee/example/MDBMessageSendTxClientExample.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Properties;
+
+/**
+ * @author Andy Taylor
+ */
+public class MDBMessageSendTxClientExample
+{
+ public static void main(String[] args) throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ //Step 1. Create an initial context to perform the JNDI lookup.
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ //Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("jms/queues/testQueue");
+
+ //Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ //Step 4.Create a JMS Connection
+ connection = cf.createConnection("guest", "password");
+
+ //Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ //Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ //Step 8. Send the Message
+ producer.send(message);
+
+ //Step 15. We lookup the reply queue
+ queue = (Queue) initialContext.lookup("jms/queues/replyQueue");
+
+ //Step 16. We create a JMS message consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ //Step 17. We start the connedction so we can receive messages
+ connection.start();
+
+ //Step 18. We receive the message and print it out
+ message = (TextMessage) messageConsumer.receive(5000);
+
+ System.out.println("message.getText() = " + message.getText());
+
+ }
+ finally
+ {
+ //Step 19. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if(connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/src/main/java/org/hornetq/javaee/example/server/MDBMessageSendTxExample.java b/examples/javaee/mdb-tx-send/src/main/java/org/hornetq/javaee/example/server/MDBMessageSendTxExample.java
new file mode 100644
index 0000000000..0e2cedcfd5
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/src/main/java/org/hornetq/javaee/example/server/MDBMessageSendTxExample.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import org.jboss.ejb3.annotation.ResourceAdapter;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+/**
+ * @author Andy Taylor
+ */
+@MessageDriven(name = "MDBMessageSendTxExample",
+ activationConfig =
+ {
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue")
+ })
+public class MDBMessageSendTxExample implements MessageListener
+{
+ @Resource(mappedName = "java:/JmsXA")
+ ConnectionFactory connectionFactory;
+
+ @Resource(mappedName = "java:/queue/replyQueue")
+ Queue replyQueue;
+
+ public void onMessage(Message message)
+ {
+ Connection conn = null;
+ try
+ {
+ //Step 9. We know the client is sending a text message so we cast
+ TextMessage textMessage = (TextMessage)message;
+
+ //Step 10. get the text from the message.
+ String text = textMessage.getText();
+
+ System.out.println("message " + text);
+
+ //Step 11. we create a JMS connection
+ conn = connectionFactory.createConnection();
+
+ //Step 12. We create a JMS session
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Step 13. we create a producer for the reply queue
+ MessageProducer producer = sess.createProducer(replyQueue);
+
+ //Step 14. we create a message and send it
+ producer.send(sess.createTextMessage("this is a reply"));
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (JMSException e)
+ {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/src/test/java/org/hornetq/javaee/examples/MDBCMTTxSendRunnerTest.java b/examples/javaee/mdb-tx-send/src/test/java/org/hornetq/javaee/examples/MDBCMTTxSendRunnerTest.java
new file mode 100644
index 0000000000..9397f52e2a
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/src/test/java/org/hornetq/javaee/examples/MDBCMTTxSendRunnerTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.MDBMessageSendTxClientExample;
+import org.hornetq.javaee.example.server.MDBMessageSendTxExample;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class MDBCMTTxSendRunnerTest
+{
+ @Deployment
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "mdb.jar");
+ ejbJar.addClass(MDBMessageSendTxExample.class);
+
+ final WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war");
+ war.addAsManifestResource("jboss-deployment-structure.xml", "jboss-deployment-structure.xml");
+ war.addAsLibrary(ejbJar);
+ System.out.println(war.toString(true));
+ return war;
+ }
+
+ @Test
+ public void runExample() throws Exception
+ {
+ MDBMessageSendTxClientExample.main(null);
+ }
+}
diff --git a/examples/javaee/mdb-tx-send/src/test/resources/arquillian.xml b/examples/javaee/mdb-tx-send/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..9090137ea7
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/mdb-tx-send/src/test/resources/jboss-deployment-structure.xml b/examples/javaee/mdb-tx-send/src/test/resources/jboss-deployment-structure.xml
new file mode 100644
index 0000000000..5bd26f867f
--- /dev/null
+++ b/examples/javaee/mdb-tx-send/src/test/resources/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/pom.xml b/examples/javaee/pom.xml
new file mode 100644
index 0000000000..e1a63b7865
--- /dev/null
+++ b/examples/javaee/pom.xml
@@ -0,0 +1,181 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples
+ hornetq-examples
+ 2.5.0-SNAPSHOT
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ pom
+ HornetQ Java EE Examples
+
+
+
+ UTF-8
+
+ ${env.JBOSS_HOME}
+
+
+ 2.5.0-SNAPSHOT
+
+
+
+
+
+ cluster-examples
+
+ mdb-remote-failover-static
+
+
+
+
+
+ jca-config
+ mdb-bmt
+ mdb-cmt-setrollbackonly
+ mdb-cmt-setrollbackonly-with-dlq
+ mdb-cmt-tx-local
+ mdb-cmt-tx-not-supported
+ mdb-cmt-tx-required
+ jms-context-injection
+ mdb-message-selector
+ mdb-tx-send
+
+
+
+
+
+ org.jboss.arquillian
+ arquillian-bom
+ 1.1.3.Final
+ import
+ pom
+
+
+
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+ org.jboss.spec
+ jboss-javaee-6.0
+ 1.0.0.Final
+ pom
+ provided
+
+
+ junit
+ junit
+ 4.8.1
+ test
+
+
+ org.jboss.arquillian.junit
+ arquillian-junit-container
+ 1.1.3.Final
+ test
+
+
+ org.wildfly
+ wildfly-arquillian-container-managed
+ 8.0.0.Final
+ test
+
+
+ org.hornetq
+ hornetq-core-client
+ ${hornetq.client.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${hornetq.client.version}
+
+
+ org.hornetq
+ hornetq-ra
+ ${hornetq.client.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.ejb3
+ jboss-ejb3-ext-api
+ 2.1.0
+
+
+ org.jboss.arquillian.protocol
+ arquillian-protocol-osgi
+ 1.0.3.Final
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ as-node-0
+ true
+ generate-test-resources
+
+ copy-resources
+
+
+ ${basedir}/target/jbossas-node0
+ true
+
+
+ ${jboss.home}
+
+ standalone/data
+ standalone/log
+ standalone/tmp
+
+
+
+ ${basedir}/server
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12
+
+ -Dlogging.configuration=file:///${user.dir}/test/config/logging.properties
+
+
+
+
+
diff --git a/examples/javaee/xarecovery/pom.xml b/examples/javaee/xarecovery/pom.xml
new file mode 100644
index 0000000000..5baeb44427
--- /dev/null
+++ b/examples/javaee/xarecovery/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+
+ org.hornetq.example.javaee
+ javaee-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-javaee-xarecovery-example
+ jar
+ HornetQ Java EE XA Recovery Example
+
\ No newline at end of file
diff --git a/examples/javaee/xarecovery/readme.html b/examples/javaee/xarecovery/readme.html
new file mode 100644
index 0000000000..50e42dbc49
--- /dev/null
+++ b/examples/javaee/xarecovery/readme.html
@@ -0,0 +1,201 @@
+
+
+ HornetQ XA Recovery Example
+
+
+
+
+
+
Java EE XA Recovery Example
+
+
This example will demonstrate XA recovery in WildFly with a HornetQ XA resource and a "buggy" XA resource.
+
+
The example application will invoke an EJB which will send a JMS message in a transaction.
+ The server will crash while the transaction has not been committed (it is in the prepared state).
+ On server restart, the transaction will be recovered and the JMS message will finally be sent.
+ The example application will then receive the message.
+
+
The example leverages the JBoss Arquillian framework to run a WildFly instance and deploy the MDB.
+
+
XA Recovery configuration
+
+
In previous versions of JBoss Application Server (the precursor to WildFly) the XA recovery configuration was manual.
+ However, in WildFly the XA recovery configuration is completely automated.
+
+
Example step-by-step
+
+
download WildFly 8.0.0.Final from here and install.
+
set the JBOSS_HOME property to point to the WildFly install directory
+
type mvn verify from the example directory to run
+
+
The example code is composed of 3 main classes:
+
+
XARecoveryExampleStepOne and XARecoveryExampleStepTwo
+
the client application to invoke the EJB and receive the message
+
XARecoveryExampleBean
+
a Stateless EJB3 which performs all the XA logic
+
+
+
Example Application
+
+
Let's take a look at XARecoveryExampleStepOne first.
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties
+
+
+
+ Properties env = new Properties();
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ initialContext = new InitialContext(env);
+
+
+
+
We look up the EJB
+
+ XARecoveryExampleService service = (XARecoveryExampleService) initialContext.lookup("ejb:/test//XARecoveryExampleBean!org.hornetq.javaee.example.server.XARecoveryExampleService");
+
+
+
We invoke the EJB's send method. This method will send a JMS text message (with the text passed in parameter)
+ and crash the server when committing the transaction
+
+ String message = "This is a text message sent at " + new Date();
+ System.out.println("invoking the EJB service with text: " + message);
+ try
+ {
+ service.send(message);
+ }
+ catch (Exception e)
+ {
+ System.out.println("#########################");
+ System.out.println("The server crashed: " + e.getMessage());
+ System.out.println("#########################");
+ }
+
+
+
At that time, the server is crashed and is automatically restarted by the test runner (i.e. XARecoveryRunnerTest).
+
+
+
Let's take a look at XARecoveryExampleStepTwo now.
+
+
+
We will try to receive a message. Once the server is restarted, the message will be recovered and the consumer will receive it.
In order to crash the server while a transaction is prepared, we will use a failingXAResource
+ which will crash the server (calling Runtime.halt()) in its commit phase.
+
We will manage ourselves the transaction and its resources enlistment/delistment to be sure that the failing XAResource
+ will crash the server after the JMS XA resources is prepared but before it is committed.
+ System.out.println("committing the tx");
+ tx.commit();
+
+
+
When the transaction is committed, it will prepare both XAResources and then commit them.
+
The failing resources will crash the server leaving the JMS XA Resource prepared but not committed
+
+
When WildFly is restarted, it will automatically trigger a recovery phase. During that phase, HornetQ resources will be
+ scanned and the prepared transaction will be recovered and committed. It is then possible to consume this message
+
+
\ No newline at end of file
diff --git a/examples/javaee/xarecovery/server/standalone/configuration/application-roles.properties b/examples/javaee/xarecovery/server/standalone/configuration/application-roles.properties
new file mode 100644
index 0000000000..0ade8fb88e
--- /dev/null
+++ b/examples/javaee/xarecovery/server/standalone/configuration/application-roles.properties
@@ -0,0 +1,22 @@
+#
+# Properties declaration of users roles for the realm 'ApplicationRealm'.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this file is as follows: -
+# username=role1,role2,role3
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined.
+#
+#admin=PowerUser,BillingAdmin,
+guest=guest
diff --git a/examples/javaee/xarecovery/server/standalone/configuration/application-users.properties b/examples/javaee/xarecovery/server/standalone/configuration/application-users.properties
new file mode 100644
index 0000000000..c52e923158
--- /dev/null
+++ b/examples/javaee/xarecovery/server/standalone/configuration/application-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ApplicationRealm' which is the default realm
+# for application services on a new AS 7.1 installation.
+#
+# This includes the following protocols: remote ejb, remote jndi, web, remote jms
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# The format of this realm is as follows: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+#
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+guest=3437456520927d113b17d471d630e0d6
diff --git a/examples/javaee/xarecovery/server/standalone/configuration/logging.properties b/examples/javaee/xarecovery/server/standalone/configuration/logging.properties
new file mode 100644
index 0000000000..8a011f0861
--- /dev/null
+++ b/examples/javaee/xarecovery/server/standalone/configuration/logging.properties
@@ -0,0 +1,52 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2010, Red Hat, Inc., and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+# Additional logger names to configure (root logger is always configured)
+loggers=org.jboss.as.config
+
+# Dump system environment at boot by default
+logger.org.jboss.as.config.level=DEBUG
+
+# Root logger level
+logger.level=${jboss.boot.server.log.level:INFO}
+# Root logger handlers
+logger.handlers=FILE,CONSOLE
+
+# Console handler configuration
+handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
+handler.CONSOLE.properties=autoFlush
+handler.CONSOLE.level=${jboss.boot.server.log.console.level:INFO}
+handler.CONSOLE.autoFlush=true
+handler.CONSOLE.formatter=PATTERN
+
+# File handler configuration
+handler.FILE=org.jboss.logmanager.handlers.FileHandler
+handler.FILE.level=DEBUG
+handler.FILE.properties=autoFlush,fileName
+handler.FILE.autoFlush=true
+handler.FILE.fileName=${org.jboss.boot.log.file:boot.log}
+handler.FILE.formatter=PATTERN
+
+# Formatter pattern configuration
+formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
+formatter.PATTERN.properties=pattern
+formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
diff --git a/examples/javaee/xarecovery/server/standalone/configuration/mgmt-users.properties b/examples/javaee/xarecovery/server/standalone/configuration/mgmt-users.properties
new file mode 100644
index 0000000000..349b00434e
--- /dev/null
+++ b/examples/javaee/xarecovery/server/standalone/configuration/mgmt-users.properties
@@ -0,0 +1,24 @@
+#
+# Properties declaration of users for the realm 'ManagementRealm' which is the default realm
+# for new AS 7.1 installations. Further authentication mechanism can be configured
+# as part of the in standalone.xml.
+#
+# Users can be added to this properties file at any time, updates after the server has started
+# will be automatically detected.
+#
+# By default the properties realm expects the entries to be in the format: -
+# username=HEX( MD5( username ':' realm ':' password))
+#
+# A utility script is provided which can be executed from the bin folder to add the users: -
+# - Linux
+# bin/add-user.sh
+#
+# - Windows
+# bin\add-user.bat
+
+# The following illustrates how an admin user could be defined, this
+# is for illustration only and does not correspond to a usable password.
+#
+#admin=2a0923285184943425d1f53ddd58ec7a
+admin=9d71b431e53d99563aa0dfca628c970b
+andy=dfb16391f1be1c454b5bce9822bd9df3
diff --git a/examples/javaee/xarecovery/server/standalone/configuration/standalone-example.xml b/examples/javaee/xarecovery/server/standalone/configuration/standalone-example.xml
new file mode 100644
index 0000000000..dbfde22493
--- /dev/null
+++ b/examples/javaee/xarecovery/server/standalone/configuration/standalone-example.xml
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ h2
+
+ sa
+ sa
+
+
+
+
+ org.h2.jdbcx.JdbcDataSource
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ 102400
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+ 10485760
+ PAGE
+ 2097152
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ${jboss.bind.address:127.0.0.1}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/XARecoveryExampleStepOne.java b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/XARecoveryExampleStepOne.java
new file mode 100644
index 0000000000..997b9f893c
--- /dev/null
+++ b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/XARecoveryExampleStepOne.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Date;
+import java.util.Properties;
+
+import org.hornetq.javaee.example.server.XARecoveryExampleService;
+
+/**
+ * An example which invokes an EJB. The EJB will be involved in a
+ * transaction with a "buggy" XAResource to crash the server.
+ * When the server is restarted, the recovery manager will recover the message
+ * so that the consumer can receive it.
+ *
+ * @author Andy Taylor
+ * @author Jeff Mesnil
+ */
+public class XARecoveryExampleStepOne
+{
+ public static void main(final String[] args) throws Exception
+ {
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Obtain an Initial Context
+ Properties env = new Properties();
+ env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ initialContext = new InitialContext(env);
+
+ // Step 2. Lookup the EJB
+ XARecoveryExampleService service = (XARecoveryExampleService) initialContext.lookup("ejb:/test//XARecoveryExampleBean!org.hornetq.javaee.example.server.XARecoveryExampleService");
+
+ // Step 3. Invoke the send method. This will crash the server
+ String message = "This is a text message sent at " + new Date();
+ System.out.println("invoking the EJB service with text: " + message);
+ try
+ {
+ service.send(message);
+ }
+ catch (Exception e)
+ {
+ System.out.println("#########################");
+ System.out.println("The server crashed: " + e.getMessage());
+ System.out.println("#########################");
+ }
+
+ // We will try to receive a message. Once the server is restarted, the message will be recovered and the consumer will receive it
+ }
+ finally
+ {
+ // Step 4. Be sure to close the resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/XARecoveryExampleStepTwo.java b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/XARecoveryExampleStepTwo.java
new file mode 100644
index 0000000000..3c57f732d4
--- /dev/null
+++ b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/XARecoveryExampleStepTwo.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.util.Date;
+import java.util.Properties;
+
+import org.hornetq.javaee.example.server.XARecoveryExampleService;
+
+/**
+ * An example which invokes an EJB. The EJB will be involved in a
+ * transaction with a "buggy" XAResource to crash the server.
+ * When the server is restarted, the recovery manager will recover the message
+ * so that the consumer can receive it.
+ *
+ * @author Andy Taylor
+ * @author Jeff Mesnil
+ */
+public class XARecoveryExampleStepTwo
+{
+ public static void main(final String[] args) throws Exception
+ {
+ // Step 1. We will try to receive a message. Once the server is restarted, the message will be recovered and the consumer will receive it.
+ boolean received = false;
+ while (!received)
+ {
+ try
+ {
+ Thread.sleep(15000);
+ XARecoveryExampleStepTwo.receiveMessage();
+ received = true;
+ }
+ catch (Exception e)
+ {
+ System.out.println(".");
+ }
+ }
+ }
+
+ private static void receiveMessage() throws Exception
+ {
+ InitialContext initialContext = null;
+ Connection connection = null;
+ try
+ {
+ final Properties env = new Properties();
+
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+
+ env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+
+ initialContext = new InitialContext(env);
+
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/RemoteConnectionFactory");
+
+ Queue queue = (Queue) initialContext.lookup("jms/queues/testQueue");
+
+ connection = cf.createConnection("guest", "password");
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ connection.start();
+
+ System.out.println("\nwaiting to receive a message...");
+ TextMessage messageReceived = (TextMessage) consumer.receive(3600 * 1000);
+ System.out.format("Received message: %s \n\t(JMS MessageID: %s)\n",
+ messageReceived.getText(),
+ messageReceived.getJMSMessageID());
+ }
+ finally
+ {
+ // Step 7. Be sure to close the resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/server/XARecoveryExampleBean.java b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/server/XARecoveryExampleBean.java
new file mode 100644
index 0000000000..55b915c3cc
--- /dev/null
+++ b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/server/XARecoveryExampleBean.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+import javax.ejb.Remote;
+import javax.ejb.Stateless;
+import javax.ejb.TransactionManagement;
+import javax.ejb.TransactionManagementType;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.TextMessage;
+import javax.jms.XAConnection;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XASession;
+import javax.naming.InitialContext;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/**
+ * An EJB which sends a JMS message in the transaction and "pauses" while the transaction
+ * is prepared so that the server can be crashed in this state.
+ * The JMS message will be recovered when the server is restarted.
+ *
+ * @author Andy Taylor
+ * @author Jeff Mesnil
+ */
+@Stateless
+@Remote(XARecoveryExampleService.class)
+@TransactionManagement(TransactionManagementType.BEAN)
+public class XARecoveryExampleBean implements XARecoveryExampleService
+{
+ public void send(final String text) throws Exception
+ {
+ InitialContext ic = null;
+ XAConnection xaConnection = null;
+ try
+ {
+ // Step 1. Create the initial context
+ ic = new InitialContext();
+
+ // Step 2. Lookup the Transaction Manager
+ TransactionManager tm = (TransactionManager)ic.lookup("java:/TransactionManager");
+
+ // Step 3. Look up the XA Connection Factory
+ XAConnectionFactory xacf = (XAConnectionFactory)ic.lookup("java:/JmsXA");
+
+ // Step 4. Look up the Queue
+ Queue queue = (Queue)ic.lookup("queue/testQueue");
+
+ // Step 5. Create a XA connection, a XA session and a message producer for the queue
+ xaConnection = xacf.createXAConnection();
+ XASession session = xaConnection.createXASession();
+ MessageProducer messageProducer = session.createProducer(queue);
+
+ // Step 6. Create a "fake" XAResource which will crash the server in its commit phase
+ XAResource failingXAResource = new FailingXAResource();
+
+ // Step 7. Begin the transaction
+ tm.begin();
+ Transaction tx = tm.getTransaction();
+
+ // Step 8. Enlist the failing XAResource
+ tx.enlistResource(failingXAResource);
+
+ // Step 9. Enlist the JMS XAResource
+ tx.enlistResource(session.getXAResource());
+
+ // Step 10. Send The Text Message
+ TextMessage message = session.createTextMessage(text);
+ messageProducer.send(message);
+ System.out.format("Sent message: %s\n\t(JMS MessageID: %s)\n", message.getText(), message.getJMSMessageID());
+
+ // Step 12. Delist the failing XAResource
+ tx.delistResource(failingXAResource, XAResource.TMSUCCESS);
+
+ // Step 13. Delist the JMS XAResource
+ tx.delistResource(session.getXAResource(), XAResource.TMSUCCESS);
+
+ // Step 14. Commit the transaction
+ // Both XA Resources will be prepared.
+ // then the failingXAResource will crash the server in its commit phase
+ // and the commit method will never be called on the JMS XA Resource: it will
+ // be in the prepared state when the server crashes
+ System.out.println("committing the tx");
+ tx.commit();
+ }
+ finally
+ {
+ // Step 15. Be sure to close all resources!
+ if (ic != null)
+ {
+ ic.close();
+ }
+ if (xaConnection != null)
+ {
+ xaConnection.close();
+ }
+ }
+ }
+
+ /**
+ * A XAResource which crashes the server in its commit phase
+ */
+ private static class FailingXAResource implements XAResource
+ {
+
+ public void commit(final Xid arg0, final boolean arg1) throws XAException
+ {
+ System.out.println("########################");
+ System.out.println("# Crashing the server! #");
+ System.out.println("########################");
+ Runtime.getRuntime().halt(1);
+ }
+
+ public void end(final Xid arg0, final int arg1) throws XAException
+ {
+ }
+
+ public void forget(final Xid arg0) throws XAException
+ {
+ }
+
+ public int getTransactionTimeout() throws XAException
+ {
+ return 0;
+ }
+
+ public boolean isSameRM(final XAResource arg0) throws XAException
+ {
+ return false;
+ }
+
+ public int prepare(final Xid arg0) throws XAException
+ {
+
+ return XAResource.XA_OK;
+ }
+
+ public Xid[] recover(final int arg0) throws XAException
+ {
+ return null;
+ }
+
+ public void rollback(final Xid arg0) throws XAException
+ {
+ }
+
+ public boolean setTransactionTimeout(final int arg0) throws XAException
+ {
+ return false;
+ }
+
+ public void start(final Xid arg0, final int arg1) throws XAException
+ {
+ }
+
+ }
+}
diff --git a/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/server/XARecoveryExampleService.java b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/server/XARecoveryExampleService.java
new file mode 100644
index 0000000000..82a7be85d8
--- /dev/null
+++ b/examples/javaee/xarecovery/src/main/java/org/hornetq/javaee/example/server/XARecoveryExampleService.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.javaee.example.server;
+
+/**
+ * An interface for the XARecoveryExampleBean EJB.
+ *
+ * @author Jeff Mesnil
+ */
+public interface XARecoveryExampleService
+{
+ void send(String text) throws Exception;
+}
diff --git a/examples/javaee/xarecovery/src/main/resources/jboss-ejb-client.properties b/examples/javaee/xarecovery/src/main/resources/jboss-ejb-client.properties
new file mode 100644
index 0000000000..fcf57ba3c0
--- /dev/null
+++ b/examples/javaee/xarecovery/src/main/resources/jboss-ejb-client.properties
@@ -0,0 +1,7 @@
+remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
+
+remote.connections=default
+
+remote.connection.default.host=localhost
+remote.connection.default.port = 8080
+remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
\ No newline at end of file
diff --git a/examples/javaee/xarecovery/src/test/java/org/hornetq/javaee/examples/XARecoveryRunnerTest.java b/examples/javaee/xarecovery/src/test/java/org/hornetq/javaee/examples/XARecoveryRunnerTest.java
new file mode 100644
index 0000000000..3dc95a6b93
--- /dev/null
+++ b/examples/javaee/xarecovery/src/test/java/org/hornetq/javaee/examples/XARecoveryRunnerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+
+package org.hornetq.javaee.examples;
+
+import org.hornetq.javaee.example.XARecoveryExampleStepOne;
+import org.hornetq.javaee.example.XARecoveryExampleStepTwo;
+import org.hornetq.javaee.example.server.XARecoveryExampleBean;
+import org.hornetq.javaee.example.server.XARecoveryExampleService;
+import org.jboss.arquillian.container.test.api.*;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.junit.InSequence;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Andy Taylor
+ * @author Justin Bertram
+ */
+@RunAsClient
+@RunWith(Arquillian.class)
+public class XARecoveryRunnerTest
+{
+ @ArquillianResource
+ private ContainerController controller;
+ @ArquillianResource
+ private Deployer deployer;
+
+ @Deployment(name = "deploy", managed = false)
+ @TargetsContainer("jboss")
+ public static Archive getDeployment()
+ {
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "ejb.jar");
+ ejbJar.addClass(XARecoveryExampleBean.class);
+ ejbJar.addClass(XARecoveryExampleService.class);
+ System.out.println(ejbJar.toString(true));
+ return ejbJar;
+ }
+
+ @Test
+ @InSequence(0)
+ public void runExample() throws Exception
+ {
+ XARecoveryExampleStepOne.main(null);
+ try
+ {
+ controller.stop("jboss");
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
+ }
+
+ @Test
+ @InSequence(1)
+ public void stepTwo() throws Exception
+ {
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("jboss");
+ XARecoveryExampleStepTwo.main(null);
+ //give the example time to run
+ Thread.sleep(10000);
+ }
+
+ @Test
+ @InSequence(-1)
+ public void startServer()
+ {
+ System.out.println("*****************************************************************************************************************************************************************");
+ controller.start("jboss");
+ System.out.println("*****************************************************************************************************************************************************************");
+ deployer.deploy("deploy");
+ }
+
+ @Test
+ @InSequence(2)
+ public void stopServer()
+ {
+ deployer.undeploy("deploy");
+ controller.stop("jboss");
+ }
+}
diff --git a/examples/javaee/xarecovery/src/test/resources/arquillian.xml b/examples/javaee/xarecovery/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..dc23f77705
--- /dev/null
+++ b/examples/javaee/xarecovery/src/test/resources/arquillian.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ ${basedir}/target/jbossas-node0
+ standalone-example.xml
+ true
+ ${node0:127.0.0.1}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/README.md b/examples/jms/README.md
new file mode 100644
index 0000000000..f95a3dbf87
--- /dev/null
+++ b/examples/jms/README.md
@@ -0,0 +1,29 @@
+Running the HornetQ Examples
+============================
+
+To run an individual example firstly cd into the example directory and run
+
+```
+mvn verify
+```
+
+If you are running against an un released version, i.e. from master branch, you will have to run `mvn install` on the root
+pom.xml and the example/hornetq-jms-examples-common/pom.xml first.
+
+If you want to run all the examples (except those that need to be run standalone) you can run `mvn verify` in the examples
+directory but before you do you will need to up the memory used by running:
+
+```
+export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m"
+```
+
+To run the javaee examples follow the instructions in examples/javaee/README.md
+
+### Recreating the examples
+
+If you are trying to copy the examples somewhere else and modifying them. Consider asking Maven to explicitly list all the dependencies:
+
+```
+# if trying to modify the 'topic' example:
+cd examples/jms/topic && mvn dependency:list
+```
diff --git a/examples/jms/aerogear/pom.xml b/examples/jms/aerogear/pom.xml
new file mode 100644
index 0000000000..e0d22e66ed
--- /dev/null
+++ b/examples/jms/aerogear/pom.xml
@@ -0,0 +1,139 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+
+
+
+
+
+
+ hornetq-jms-aerogear-example
+ jar
+ HornetQ JMS AeroGear Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ endpoint
+ ${endpoint}
+
+
+ applicationid
+ ${applicationid}
+
+
+ mastersecret
+ ${mastersecret}
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.AerogearExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-aerogear-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-aerogear-integration
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/aerogear/readme.html b/examples/jms/aerogear/readme.html
new file mode 100644
index 0000000000..66112a0aef
--- /dev/null
+++ b/examples/jms/aerogear/readme.html
@@ -0,0 +1,135 @@
+
+
+ HornetQ JMS AeroGear Example
+
+
+
+
+
+
JMS AeroGear Example
+
+
This example shows how you can send a message to a mobile device by leveraging AeroGears push technology which
+ provides support for different push notification technologies like Google Cloud Messaging, Apple's APNs or
+ Mozilla's SimplePush.
+
+
For this example you will need an AeroGear Application running somewhere, a good way to do this is to deploy the
+ Push Application on openshift, you can follow the AeroGear Push 0.X Quickstart.
+
+
Once you have created your AeroGear Push Application you can create a mobile application. Simply log into the application
+ on the web and create a new mobile application by clicking the 'create' button. Once created you will see an application id
+ and a master secret, you will need the later to run the example.
+
+
lastly you will need to create a variant. For this example we will be using Android so you will need to create a google project,
+ this article explains how to do this.
+ Once created click on your app then click 'add' to add a variant. choose 'google cloud messaging', enter your google
+ API key and the project number from your google project and click create
+
+
Now before we run the example we need a mobile application to receive it. Writing a mobile app is beyond the scope
+ of this example but for testing purposes we have supplied an Android app you can use, simply install on your android phone.
+ It can be found here. For a more in depth mobile
+ app example visit the AeroGear site.
+
+
Once you have installed the mobile app you will need to configure the following:
+
AeroGear Unified Push URL : This is the URL where your aerogear server is running, something like http://myapp-mydomain.rhcloud.com
+ AeroGear Variant ID : This is the ID of the variant you created in AeroGear
+ AeroGear Variant Secret : This is the secret for your variant
+ GCM Sender ID : this is the Google project Number you created on Google
+ Variant : you can use this to target messages if needed.
+
+
+
Once you set all these correctly you should get a message saying your mobile app is registered, if you log into
+ your AeroGear app you should see it registered with the variant.
+
+
+
Now to run the example simply run the following command
+ 'mvn -Dendpoint=my aerogear url -Dapplicationid=my application id -Dmastersecret=my master secret -Djsse.enableSNIExtension=false clean verify'.
+ If you arent using java 7 you can omit the 'jsse.enableSNIExtension=false'
+
+
You should see something like this in your HornetQServer
+
+
+
+ Dec 04, 2013 3:25:39 PM org.jboss.aerogear.unifiedpush.SenderClient submitPayload
+ INFO: HTTP Response code from UnifiedPush Server: 302
+ Dec 04, 2013 3:25:39 PM org.jboss.aerogear.unifiedpush.SenderClient submitPayload
+ INFO: Performing redirect to 'https://myapp-mydomain.rhcloud.com/rest/sender/'
+ Dec 04, 2013 3:25:40 PM org.jboss.aerogear.unifiedpush.SenderClient submitPayload
+ INFO: HTTP Response code from UnifiedPush Server: 200
+
+
+
+
And on your mobile app you should see a message from HornetQ
+
+
Now lets look a bit more closely at the configuration in hornetq-configuration.xml
Firstly you will see that we have to create a core queue so it is available when the connector is started, the following are mandatory parameters:
+
+
endpoint - The endpoint or URL of you AeroGear application
+
queue - The name of the queue to consume from
+
application-id - The application id of your mobile application in AeroGear
+
master-secret - the secret of your mobile application in AeroGear
+
+
as well as those there are also the following optional parameters
+
+
ttl - The time to live for the message once AeroGear receives it
+
badge - The badge the mobile app should use for the notification
+
sound - The sound the mobile app should use for the notification
+
filter - A message filter(selector) to use on the connector
+
retry-interval - If an error occurs on send, how long before we try again
+
retry-attempts - How many times we should try to reconnect after an error
+
variants - A comma separated list of variants that should get the message
+
aliases - A list of aliases that should get the message
+
device-types - A list of device types that should get the message
+
+
More in depth explanations of these can be found in the AeroGear docs.
+
Now lets look at a snippet of code we used to send the message for our JMS client
+
+
+ Queue queue = (Queue)initialContext.lookup("/queue/aerogearQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ Message message = session.createMessage();
+
+ message.setStringProperty("AEROGEAR_ALERT", "Hello this is a notification from HornetQ");
+
+ producer.send(message);
+
+
+
The most important thing here is string propert we have set on the message, i.e. 'AEROGEAR_ALERT'. This is the
+ actual alert that is sent via AeroGear
+
As well as the alert itself you can override any of the above optional parameters in the same fashionby using the
+ following propert names: AEROGEAR_SOUND,AEROGEAR_BADGE,AEROGEAR_TTL,AEROGEAR_VARIANTS,AEROGEAR_ALIASES and AEROGEAR_DEVICE_TYPES
+
+
\ No newline at end of file
diff --git a/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java b/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java
new file mode 100644
index 0000000000..a0d285aed4
--- /dev/null
+++ b/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple JMS Queue example that creates a producer and consumer on a queue and sends then receives a message.
+ *
+ * @author Andy Taylor
+ */
+public class AerogearExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new AerogearExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/aerogearQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ Message message = session.createMessage();
+
+ message.setStringProperty("AEROGEAR_ALERT", "Hello this is a notification from HornetQ");
+
+ producer.send(message);
+
+ System.out.println("Sent message");
+
+ System.out.println("now check your mobile app and press enter");
+
+ System.in.read();
+
+ return true;
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..6100121cd9
--- /dev/null
+++ b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,61 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ jms.queue.aerogearQueue
+
+
+
+
+
+ org.hornetq.integration.aerogear.AeroGearConnectorServiceFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..cde44e7b0e
--- /dev/null
+++ b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/applet/applet.html b/examples/jms/applet/applet.html
new file mode 100644
index 0000000000..f7b7b80380
--- /dev/null
+++ b/examples/jms/applet/applet.html
@@ -0,0 +1,17 @@
+
+
+ HornetQ Applet Example
+
+
+
HornetQ Applet Example
+
+
The Applet will connect to HornetQ server running on localhost and
+ publishes messages on a topic exampleTopic when "Send" is pressed.
+
The Applet is also a MessageListener and will display messages received from the topic
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/bridge/src/main/java/org/hornetq/jms/example/BridgeExample.java b/examples/jms/bridge/src/main/java/org/hornetq/jms/example/BridgeExample.java
new file mode 100644
index 0000000000..79a36e3ae4
--- /dev/null
+++ b/examples/jms/bridge/src/main/java/org/hornetq/jms/example/BridgeExample.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * This example demonstrates a core bridge set-up between two nodes, consuming messages from a queue
+ * on one node and forwarding them to an address on the second node.
+ *
+ * @author Tim Fox
+ *
+ *
+ */
+public class HatColourChangeTransformer implements Transformer
+{
+ public ServerMessage transform(final ServerMessage message)
+ {
+ SimpleString propName = new SimpleString("hat");
+
+ SimpleString oldProp = message.getSimpleStringProperty(propName);
+
+ // System.out.println("Old hat colour is " + oldProp);
+
+ // Change the colour
+ message.putStringProperty(propName, new SimpleString("blue"));
+
+ return message;
+ }
+
+}
diff --git a/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..728117aa95
--- /dev/null
+++ b/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,72 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ jms.queue.sausage-factory
+
+
+
+
+
+
+ jms.queue.sausage-factory
+ jms.queue.mincing-machine
+
+ org.hornetq.jms.example.HatColourChangeTransformer
+ -1
+
+ remote-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..8f77abe127
--- /dev/null
+++ b/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/bridge/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-configuration.xml
new file mode 100644
index 0000000000..f84aecd0c5
--- /dev/null
+++ b/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-configuration.xml
@@ -0,0 +1,44 @@
+
+
+ ${build.directory}/server1/data/messaging/bindings
+
+ ${build.directory}/server1/data/messaging/journal
+
+ ${build.directory}/server1/data/messaging/largemessages
+
+ ${build.directory}/server1/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-jms.xml
new file mode 100644
index 0000000000..23fb3701b1
--- /dev/null
+++ b/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/bridge/src/main/resources/hornetq/server1/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/browser/pom.xml b/examples/jms/browser/pom.xml
new file mode 100644
index 0000000000..a0a3f96af8
--- /dev/null
+++ b/examples/jms/browser/pom.xml
@@ -0,0 +1,114 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-browser-example
+ jar
+ HornetQ JMS Browser Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.QueueBrowserExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-browser-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/browser/readme.html b/examples/jms/browser/readme.html
new file mode 100644
index 0000000000..42551aed1c
--- /dev/null
+++ b/examples/jms/browser/readme.html
@@ -0,0 +1,128 @@
+
+
+ HornetQ JMS QueueBrowser Example
+
+
+
+
+
+
JMS QueueBrowser Example
+
+
This example shows you how to use a JMS QueueBrowser with HornetQ.
+ Queues are a standard part of JMS, please consult the JMS 1.1 specification for full details.
+ A QueueBrowser is used to look at messages on the queue without removing them.
+ It can scan the entire content of a queue or only messages matching a message selector.
+
+ The example will send 2 messages on a queue, use a QueueBrowser to browse
+ the queue (looking at the message without removing them) and finally consume the 2 messages
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
We create 2 JMS text messages that we are going to send.
+
+ TextMessage message_1 = session.createTextMessage("this is the 1st message");
+ TextMessage message_2 = session.createTextMessage("this is the 2nd message");
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/browser/src/main/java/org/hornetq/jms/example/QueueBrowserExample.java b/examples/jms/browser/src/main/java/org/hornetq/jms/example/QueueBrowserExample.java
new file mode 100644
index 0000000000..d4204e121e
--- /dev/null
+++ b/examples/jms/browser/src/main/java/org/hornetq/jms/example/QueueBrowserExample.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.util.Enumeration;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple example which shows how to use a QueueBrowser to look at messages of a queue without removing them from the queue
+ *
+ * @author Jeff Mesnil
+ *
+ *
+ */
+public class QueueBrowserExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new QueueBrowserExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4. Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create 2 Text Messages
+ TextMessage message_1 = session.createTextMessage("this is the 1st message");
+ TextMessage message_2 = session.createTextMessage("this is the 2nd message");
+
+ // Step 8. Send the Message
+ producer.send(message_1);
+ producer.send(message_2);
+
+ // Step 9. Create the JMS QueueBrowser
+ QueueBrowser browser = session.createBrowser(queue);
+
+ // Step 10. Browse the messages on the queue
+ // Browsing a queue does not remove the messages from the queue
+ Enumeration messageEnum = browser.getEnumeration();
+ while (messageEnum.hasMoreElements())
+ {
+ TextMessage message = (TextMessage)messageEnum.nextElement();
+ System.out.println("Browsing: " + message.getText());
+ }
+
+ // Step 11. Close the browser
+ browser.close();
+
+ // Step 12. Create a JMS Message Consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 13. Start the Connection
+ connection.start();
+
+ // Step 14. Receive the 2 messages
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("Received message: " + messageReceived.getText());
+ messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("Received message: " + messageReceived.getText());
+
+ return true;
+
+ }
+ finally
+ {
+ // Step 15. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+}
diff --git a/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..9584a6b1c1
--- /dev/null
+++ b/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,42 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..678e7f5214
--- /dev/null
+++ b/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/browser/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/client-kickoff/pom.xml b/examples/jms/client-kickoff/pom.xml
new file mode 100644
index 0000000000..48ce373bbd
--- /dev/null
+++ b/examples/jms/client-kickoff/pom.xml
@@ -0,0 +1,139 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-client-kickoff-example
+ jar
+ HornetQ JMS Kick Off Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+ true
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ com.sun.management.jmxremote
+
+
+
+ com.sun.management.jmxremote.port
+ 3000
+
+
+ com.sun.management.jmxremote.ssl
+ false
+
+
+ com.sun.management.jmxremote.authenticate
+ false
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.ClientKickoffExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-client-kickoff-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/client-kickoff/readme.html b/examples/jms/client-kickoff/readme.html
new file mode 100644
index 0000000000..23a95ac80e
--- /dev/null
+++ b/examples/jms/client-kickoff/readme.html
@@ -0,0 +1,137 @@
+
+
+ HornetQ Client Kickoff Example
+
+
+
+
+
+
Client Kickoff Example
+
+
This example shows how to kick off a client connected to HornetQ
+ using JMX
+
+
The example will connect to HornetQ. Using JMX, we will list the remote addresses connected to the
+ server and close the corresponding connections. The client will be kicked off from HornetQ receiving
+ an exception that its JMS connection was interrupted.
+
+
Example configuration
+
+
HornetQ exposes its managed resources by default on the platform MBeanServer.
+
To access this MBeanServer remotely, the Java Virtual machine must be started with system properties:
+
These properties are explained in the Java 5 Management guide
+ (please note that for this example, we will disable user authentication for simplicity).
+
With these properties, HornetQ server will be manageable remotely using standard JMX URL on port 3000.
+
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get its properties from client-jndi.properties
We set a ExceptionListener on the connection to be notified after a problem occurred
+
+ final AtomicReference<JMSException> exception = new AtomicReference<JMSException>();
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exception.set(e);
+ }
+ });
+
+
+
We start the connection
+
+ connection.start();
+
+
+
We create a MBean proxy to the HornetQServerControlMBean used to manage HornetQ server
+ (see JMX example for a complete explanation of the different steps)
+ org.hornetq.jms.example.SpawnedJMSServer out:11:22:33,034 WARN @RMI TCP Connection(3)-192.168.0.10 [RemotingConnectionImpl] Connection failure has been detected connections for /192.168.0.10:52707 closed by management:0
+ org.hornetq.jms.example.SpawnedJMSServer out:11:22:33,035 WARN @RMI TCP Connection(3)-192.168.0.10 [ServerSessionImpl] Client connection failed, clearing up resources for session 4646da35-2fe8-11de-9ce9-752ccc2b26e4
+ org.hornetq.jms.example.SpawnedJMSServer out:11:22:33,035 WARN @RMI TCP Connection(3)-192.168.0.10 [ServerSessionImpl] Cleared up resources for session 4646da35-2fe8-11de-9ce9-752ccc2b26e4
+
+
+
+
We display the exception received by the connection's ExceptionListener
+
+ exception.get().printStackTrace();
+
+
+
When the connection was closed on the server-side by the call to serverControl.closeConnectionsForAddress(),
+ the client's connection was disconnected and its exception listener was notified.
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
\ No newline at end of file
diff --git a/examples/jms/client-kickoff/src/main/java/org/hornetq/jms/example/ClientKickoffExample.java b/examples/jms/client-kickoff/src/main/java/org/hornetq/jms/example/ClientKickoffExample.java
new file mode 100644
index 0000000000..6923faa410
--- /dev/null
+++ b/examples/jms/client-kickoff/src/main/java/org/hornetq/jms/example/ClientKickoffExample.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.naming.InitialContext;
+
+import org.hornetq.api.core.management.HornetQServerControl;
+import org.hornetq.api.core.management.ObjectNameBuilder;
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * An example that shows how to kick off a client connected to HornetQ by using JMX.
+ *
+ * @author Jeff Mesnil
+ */
+public class ClientKickoffExample extends HornetQExample
+{
+ private static final String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi";
+
+ public static void main(final String[] args)
+ {
+ new ClientKickoffExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ QueueConnection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perform a lookup on the Connection Factory
+ QueueConnectionFactory cf = (QueueConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 3.Create a JMS Connection
+ connection = cf.createQueueConnection();
+
+ // Step 4. Set an exception listener on the connection to be notified after a problem occurred
+ final AtomicReference exception = new AtomicReference();
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ @Override
+ public void onException(final JMSException e)
+ {
+ exception.set(e);
+ }
+ });
+
+ // Step 5. We start the connection
+ connection.start();
+
+ // Step 6. Create a HornetQServerControlMBean proxy to manage the server
+ ObjectName on = ObjectNameBuilder.DEFAULT.getHornetQServerObjectName();
+ JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(JMX_URL), new HashMap());
+ MBeanServerConnection mbsc = connector.getMBeanServerConnection();
+ HornetQServerControl serverControl = MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ on,
+ HornetQServerControl.class,
+ false);
+
+ // Step 7. List the remote address connected to the server
+ System.out.println("List of remote addresses connected to the server:");
+ System.out.println("----------------------------------");
+ String[] remoteAddresses = serverControl.listRemoteAddresses();
+ for (String remoteAddress : remoteAddresses)
+ {
+ System.out.println(remoteAddress);
+ }
+ System.out.println("----------------------------------");
+
+ // Step 8. Close the connections for the 1st remote address and kickoff the client
+ serverControl.closeConnectionsForAddress(remoteAddresses[0]);
+
+ // Sleep a little bit so that the stack trace from the server won't be
+ // mingled with the JMSException received on the ExceptionListener
+ Thread.sleep(1000);
+
+ // Step 9. Display the exception received by the connection's ExceptionListener
+ System.err.println("\nException received from the server:");
+ System.err.println("----------------------------------");
+ exception.get().printStackTrace();
+ System.err.println("----------------------------------");
+
+ return true;
+ }
+ finally
+ {
+ // Step 10. Be sure to close the resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..8acfd26f2f
--- /dev/null
+++ b/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,30 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+ true
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
diff --git a/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..b0e4f893a6
--- /dev/null
+++ b/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/client-kickoff/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/client-side-failoverlistener/pom.xml b/examples/jms/client-side-failoverlistener/pom.xml
new file mode 100644
index 0000000000..b940f17426
--- /dev/null
+++ b/examples/jms/client-side-failoverlistener/pom.xml
@@ -0,0 +1,168 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-client-side-fileoverlistener-example
+ jar
+ HornetQ JMS Client Side Failover listener Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.ClientSideFailoverListerExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-client-side-fileoverlistener-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
diff --git a/examples/jms/client-side-failoverlistener/readme.html b/examples/jms/client-side-failoverlistener/readme.html
new file mode 100644
index 0000000000..b67642be67
--- /dev/null
+++ b/examples/jms/client-side-failoverlistener/readme.html
@@ -0,0 +1,94 @@
+
+
+ HornetQ Client Side Failover Listener Example
+
+
+
+
+
+
Client Side Kickoff Example
+
+
This example demonstrates how you can listen on failover event on the client side.
+
+
In this example there are two nodes running in a cluster, both server will be running for start,
+ but after a while the first server will crash. This will trigger an fail oever event.
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get its properties from client-jndi.properties
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage messageA = sessionA.createTextMessage("A:This is text message " + i);
+ producerA.send(messageA);
+ System.out.println("Sent message: " + messageA.getText());
+ }
+
+
+
+
We start the connection to consume messages
+
+ connectionA.start();
+
+
+
We consume messages from the session A, one at a time. We reached message no 5 the first server will crash
+
+ consume(sessionA, queue, numMessages, "A");
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
diff --git a/examples/jms/clustered-jgroups/src/main/java/org/hornetq/jms/example/ClusteredJgroupsExample.java b/examples/jms/clustered-jgroups/src/main/java/org/hornetq/jms/example/ClusteredJgroupsExample.java
new file mode 100644
index 0000000000..9cb3395ede
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/java/org/hornetq/jms/example/ClusteredJgroupsExample.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple example that demonstrates clustering using jgroups.
+ *
+ * @author Howard Gao
+ */
+public class ClusteredJgroupsExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new ClusteredJgroupsExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection0 = null;
+
+ Connection connection1 = null;
+
+ InitialContext ic0 = null;
+
+ InitialContext ic1 = null;
+
+ try
+ {
+ // Step 1. Get an initial context for looking up JNDI from server 0
+ ic0 = getContext(0);
+
+ // Step 2. Look-up the JMS Queue object from JNDI
+ Queue queue = (Queue)ic0.lookup("/queue/exampleQueue");
+
+ // Step 3. Look-up a JMS Connection Factory object from JNDI on server 0
+ ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+
+ // Step 4. Get an initial context for looking up JNDI from server 1
+ ic1 = getContext(1);
+
+ // Step 5. Look-up a JMS Connection Factory object from JNDI on server 1
+ ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+
+ // Step 6. We create a JMS Connection connection0 which is a connection to server 0
+ connection0 = cf0.createConnection();
+
+ // Step 7. We create a JMS Connection connection1 which is a connection to server 1
+ connection1 = cf1.createConnection();
+
+ // Step 8. We create a JMS Session on server 0
+ Session session0 = connection0.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 9. We create a JMS Session on server 1
+ Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 10. We start the connections to ensure delivery occurs on them
+ connection0.start();
+
+ connection1.start();
+
+ // Step 11. We create JMS MessageConsumer objects on server 0 and server 1
+ MessageConsumer consumer0 = session0.createConsumer(queue);
+
+ MessageConsumer consumer1 = session1.createConsumer(queue);
+
+ Thread.sleep(1000);
+
+ // Step 12. We create a JMS MessageProducer object on server 0
+ MessageProducer producer = session0.createProducer(queue);
+
+ // Step 13. We send some messages to server 0
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+
+ // Step 14. We now consume those messages on *both* server 0 and server 1.
+ // We note the messages have been distributed between servers in a round robin fashion
+ // JMS Queues implement point-to-point message where each message is only ever consumed by a
+ // maximum of one consumer
+
+ for (int i = 0; i < numMessages; i += 2)
+ {
+ TextMessage message0 = (TextMessage)consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node 0");
+
+ TextMessage message1 = (TextMessage)consumer1.receive(5000);
+
+ System.out.println("Got message: " + message1.getText() + " from node 1");
+ }
+
+ return true;
+ }
+ finally
+ {
+ // Step 15. Be sure to close our resources!
+
+ if (connection0 != null)
+ {
+ connection0.close();
+ }
+
+ if (connection1 != null)
+ {
+ connection1.close();
+ }
+
+ if (ic0 != null)
+ {
+ ic0.close();
+ }
+
+ if (ic1 != null)
+ {
+ ic1.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/client-jndi.properties b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/client-jndi.properties
new file mode 100644
index 0000000000..080524fbb8
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/client-jndi.properties
@@ -0,0 +1,3 @@
+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
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-beans.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..61c04e6193
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-beans.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..9e7bb79934
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,76 @@
+
+
+
+ server0/paging
+
+ server0/bindings
+
+ server0/journal
+
+ server0/large-messages
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+ 5000
+ test-jgroups-file_ping.xml
+ hornetq_broadcast_channel
+ netty-connector
+
+
+
+
+
+ test-jgroups-file_ping.xml
+ hornetq_broadcast_channel
+ 10000
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..678e7f5214
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/test-jgroups-file_ping.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/test-jgroups-file_ping.xml
new file mode 100644
index 0000000000..269e06ea70
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server0/test-jgroups-file_ping.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/client-jndi.properties b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/client-jndi.properties
new file mode 100644
index 0000000000..7bcaf955be
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/client-jndi.properties
@@ -0,0 +1,3 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://localhost:2099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-beans.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-beans.xml
new file mode 100644
index 0000000000..e5fe1e0fd7
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-beans.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+ 2099
+ localhost
+ 2098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-configuration.xml
new file mode 100644
index 0000000000..d3525a744c
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-configuration.xml
@@ -0,0 +1,75 @@
+
+
+
+ server1/paging
+
+ server1/bindings
+
+ server1/journal
+
+ server1/large-messages
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+ 5000
+ test-jgroups-file_ping.xml
+ hornetq_broadcast_channel
+ netty-connector
+
+
+
+
+
+ test-jgroups-file_ping.xml
+ hornetq_broadcast_channel
+ 10000
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-jms.xml
new file mode 100644
index 0000000000..678e7f5214
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/test-jgroups-file_ping.xml b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/test-jgroups-file_ping.xml
new file mode 100644
index 0000000000..38ad1441a8
--- /dev/null
+++ b/examples/jms/clustered-jgroups/src/main/resources/hornetq/server1/test-jgroups-file_ping.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-queue/pom.xml b/examples/jms/clustered-queue/pom.xml
new file mode 100644
index 0000000000..01d3de3f95
--- /dev/null
+++ b/examples/jms/clustered-queue/pom.xml
@@ -0,0 +1,147 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ clustered-queue
+ jar
+ HornetQ JMS Clustered Queue Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.ClusteredQueueExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+
+
+ org.hornetq.examples.jms
+ clustered-queue
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-queue/readme.html b/examples/jms/clustered-queue/readme.html
new file mode 100644
index 0000000000..9ac1c06137
--- /dev/null
+++ b/examples/jms/clustered-queue/readme.html
@@ -0,0 +1,177 @@
+
+
+ HornetQ JMS Load Balanced Clustered Queue Example
+
+
+
+
+
+
JMS Load Balanced Clustered Queue Example
+
+
This example demonstrates a JMS queue deployed on two different nodes. The two nodes are configured to form a cluster.
+
We then create a consumer on the queue on each node, and we create a producer on only one of the nodes.
+
We then send some messages via the producer, and we verify that both consumers receive the sent messages
+ in a round-robin fashion.
+
In other words, HornetQ load balances the sent messages across all consumers on the cluster
+
This example uses JNDI to lookup the JMS Queue and ConnectionFactory objects. If you prefer not to use
+ JNDI, these could be instantiated directly.
+
Here's the relevant snippet from the server configuration, which tells the server to form a cluster between the two nodes
+ and to load balance the messages between the nodes.
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+
+
+
+
We now consume those messages on *both* server 0 and server 1.
+ We note the messages have been distributed between servers in a round robin fashion.
+ HornetQ has load balanced the messages between the available consumers on the different nodes.
+ HornetQ can be configured to always load balance messages to all nodes, or to only balance messages
+ to nodes which have consumers with no or matching selectors. See the user manual for more details.
+ JMS Queues implement point-to-point message where each message is only ever consumed by a
+ maximum of one consumer.
+
+
+ for (int i = 0; i < numMessages; i += 2)
+ {
+ TextMessage message0 = (TextMessage)consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node 0");
+
+ TextMessage message1 = (TextMessage)consumer1.receive(5000);
+
+ System.out.println("Got message: " + message1.getText() + " from node 1");
+ }
+
+
+
+
And finally (no pun intended), always remember to close your JMS resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
This example demonstrates a JMS queue deployed on two different nodes. The two nodes are configured to form a cluster
+ from a static list of nodes.
+
We then create a consumer on the queue on each node, and we create a producer on only one of the nodes.
+
We then send some messages via the producer, and we verify that both consumers receive the sent messages
+ in a round-robin fashion.
+
In other words, HornetQ load balances the sent messages across all consumers on the cluster
+
This example uses JNDI to lookup the JMS Queue and ConnectionFactory objects. If you prefer not to use
+ JNDI, these could be instantiated directly.
+
Here's the relevant snippet from the server configuration, which tells the server to form a cluster between the two nodes
+ and to load balance the messages between the nodes.
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+
+
+
+
We now consume those messages on *both* server 0 and server 1.
+ We note the messages have been distributed between servers in a round robin fashion.
+ HornetQ has load balanced the messages between the available consumers on the different nodes.
+ HornetQ can be configured to always load balance messages to all nodes, or to only balance messages
+ to nodes which have consumers with no or matching selectors. See the user manual for more details.
+ JMS Queues implement point-to-point message where each message is only ever consumed by a
+ maximum of one consumer.
+
+
+ for (int i = 0; i < numMessages; i += 2)
+ {
+ TextMessage message0 = (TextMessage)consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node 0");
+
+ TextMessage message1 = (TextMessage)consumer1.receive(5000);
+
+ System.out.println("Got message: " + message1.getText() + " from node 1");
+ }
+
+
+
+
And finally (no pun intended), always remember to close your JMS resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/java/org/hornetq/jms/example/StaticClusteredQueueExample.java b/examples/jms/clustered-static-discovery/src/main/java/org/hornetq/jms/example/StaticClusteredQueueExample.java
new file mode 100644
index 0000000000..48fa28f6d1
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/java/org/hornetq/jms/example/StaticClusteredQueueExample.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple example that demonstrates server side load-balancing of messages between the queue instances on different
+ * nodes of the cluster. The cluster is created from a static list of nodes.
+ *
+ * @author Jeff Mesnil
+ */
+public class StaticClusteredQueueExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new StaticClusteredQueueExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection initialConnection = null;
+
+ Connection connection0 = null;
+
+ Connection connection1 = null;
+
+ Connection connection2 = null;
+
+ Connection connection3 = null;
+
+ InitialContext ic0 = null;
+
+ try
+ {
+ // Step 1. Get an initial context for looking up JNDI from server 0
+ ic0 = getContext(3);
+
+ // Step 2. Look-up the JMS Queue object from JNDI
+ Queue queue = (Queue)ic0.lookup("/queue/exampleQueue");
+
+ // Step 3. Look-up a JMS Connection Factory object from JNDI on server 0
+ ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+
+ //grab an initial connection and wait, in reality you wouldn't do it this way but since we want to ensure an
+ // equal load balance we do this and then create 4 connections round robined
+ initialConnection = cf0.createConnection();
+
+ Thread.sleep(2000);
+ // Step 6. We create a JMS Connection connection0 which is a connection to server 0
+ connection0 = cf0.createConnection();
+
+ // Step 7. We create a JMS Connection connection1 which is a connection to server 1
+ connection1 = cf0.createConnection();
+
+ // Step 6. We create a JMS Connection connection0 which is a connection to server 0
+ connection2 = cf0.createConnection();
+
+ // Step 7. We create a JMS Connection connection1 which is a connection to server 1
+ connection3 = cf0.createConnection();
+
+ // Step 8. We create a JMS Session on server 0
+ Session session0 = connection0.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 9. We create a JMS Session on server 1
+ Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+
+ // Step 8. We create a JMS Session on server 0
+ Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 9. We create a JMS Session on server 1
+ Session session3 = connection3.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 10. We start the connections to ensure delivery occurs on them
+ connection0.start();
+
+ connection1.start();
+
+ connection2.start();
+
+ connection3.start();
+
+ // Step 11. We create JMS MessageConsumer objects on server 0 and server 1
+ MessageConsumer consumer0 = session0.createConsumer(queue);
+
+ MessageConsumer consumer1 = session1.createConsumer(queue);
+
+ MessageConsumer consumer2 = session2.createConsumer(queue);
+
+ MessageConsumer consumer3 = session3.createConsumer(queue);
+
+ Thread.sleep(2000);
+
+ // Step 12. We create a JMS MessageProducer object on server 3
+ MessageProducer producer = session3.createProducer(queue);
+
+ // Step 13. We send some messages to server 0
+
+ final int numMessages = 20;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+ Thread.sleep(2000);
+ // Step 14. We now consume those messages on *both* server 0 and server 1.
+ // We note the messages have been distributed between servers in a round robin fashion
+ // JMS Queues implement point-to-point message where each message is only ever consumed by a
+ // maximum of one consumer
+ int con0Node = getServer(connection0);
+ int con1Node = getServer(connection1);
+ int con2Node = getServer(connection2);
+ int con3Node = getServer(connection3);
+
+ if(con0Node + con1Node + con2Node + con3Node != 6)
+ {
+ return false;
+ }
+ for (int i = 0; i < numMessages; i += 4)
+ {
+ TextMessage message0 = (TextMessage)consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node " + con0Node);
+
+ TextMessage message1 = (TextMessage)consumer1.receive(5000);
+
+ System.out.println("Got message: " + message1.getText() + " from node " + con1Node);
+
+ TextMessage message2 = (TextMessage)consumer2.receive(5000);
+
+ System.out.println("Got message: " + message2.getText() + " from node " + con2Node);
+
+ TextMessage message3 = (TextMessage)consumer3.receive(5000);
+
+ System.out.println("Got message: " + message3.getText() + " from node " + con3Node);
+ }
+
+ return true;
+ }
+ finally
+ {
+ // Step 15. Be sure to close our resources!
+
+ if (initialConnection != null)
+ {
+ initialConnection.close();
+ }
+
+ if (connection0 != null)
+ {
+ connection0.close();
+ }
+
+ if (connection1 != null)
+ {
+ connection1.close();
+ }
+
+ if (connection2 != null)
+ {
+ connection2.close();
+ }
+
+ if (connection3 != null)
+ {
+ connection3.close();
+ }
+
+ if (ic0 != null)
+ {
+ ic0.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..cac16b22bd
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,64 @@
+
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+ server1-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..6156e3c2fd
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/jndi.properties b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server0/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-configuration.xml
new file mode 100644
index 0000000000..73cc56eaf8
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-configuration.xml
@@ -0,0 +1,64 @@
+
+
+
+ ${build.directory}/server1/data/messaging/bindings
+
+ ${build.directory}/server1/data/messaging/journal
+
+ ${build.directory}/server1/data/messaging/largemessages
+
+ ${build.directory}/server1/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+ server0-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-jms.xml
new file mode 100644
index 0000000000..6156e3c2fd
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-jms.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/jndi.properties b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server1/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-configuration.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-configuration.xml
new file mode 100644
index 0000000000..283121a90f
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-configuration.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+ ${build.directory}/server2/data/messaging/bindings
+
+ ${build.directory}/server2/data/messaging/journal
+
+ ${build.directory}/server2/data/messaging/largemessages
+
+ ${build.directory}/server2/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+ server0-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-jms.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-jms.xml
new file mode 100644
index 0000000000..abd44d82ea
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-jms.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-users.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/jndi.properties b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/jndi.properties
new file mode 100644
index 0000000000..629072e931
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server2/jndi.properties
@@ -0,0 +1,15 @@
+#
+# Copyright 2009 Red Hat, Inc.
+# Red Hat 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.
+#
+
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-configuration.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-configuration.xml
new file mode 100644
index 0000000000..78503b493a
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-configuration.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+ ${build.directory}/server3/data/messaging/bindings
+
+ ${build.directory}/server3/data/messaging/journal
+
+ ${build.directory}/server3/data/messaging/largemessages
+
+ ${build.directory}/server3/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+ server0-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-jms.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-jms.xml
new file mode 100644
index 0000000000..abd44d82ea
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-jms.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-users.xml b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/jndi.properties b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/examples/jms/clustered-static-discovery/src/main/resources/hornetq/server3/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/pom.xml b/examples/jms/clustered-static-oneway/pom.xml
new file mode 100644
index 0000000000..4ed9488357
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/pom.xml
@@ -0,0 +1,169 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-clustered-static-oneway-example
+ jar
+ HornetQ JMS Clustered Static One Way Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+
+ start2
+
+ start
+
+
+ 1299
+ 1298
+ ${basedir}/target/classes/hornetq/server2
+ true
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.ClusterStaticOnewayExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+ jnp://localhost:1299
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+ stop2
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server2
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-clustered-static-oneway-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/readme.html b/examples/jms/clustered-static-oneway/readme.html
new file mode 100644
index 0000000000..73726212d5
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/readme.html
@@ -0,0 +1,229 @@
+
+
+ HornetQ JMS Load Balanced Static Clustered Queue Example
+
+
+
+
+
+
JMS Load Balanced Static Clustered One Way Queue Example
+
+
This example demonstrates a JMS queue deployed on three different nodes. The three nodes are configured to form a one way cluster
+ from a static list of nodes.
+
A one way cluster is different from a symmetrical cluster in that each node is only connected to one another node in
+ a chain type fashion, so server 0 -> server 1 -> server 2
+
We then create a consumer on the queue on each node, and we create a producer on only one of the nodes.
+
We then send some messages via the producer, and we verify that all consumers receive the sent messages
+ in a round-robin fashion.
+
In other words, HornetQ load balances the sent messages across all consumers on the cluster
+
This example uses JNDI to lookup the JMS Queue and ConnectionFactory objects. If you prefer not to use
+ JNDI, these could be instantiated directly.
+
Here's the relevant snippet from the server configuration, which tells the server to form a one way cluster between the three nodes
+ and to load balance the messages between the nodes. Note that we have set allow-direct-connections-only to true,
+ this means that this server will only ever connect the address's specified in the list of connectors. ALso notice
+ that max-hops is 2, this is because server 0 is not directly connected to server 2, 2 hops in fact, so we
+ allow any updates from servers up to 2 hops away
grab an initial connection and wait, in reality you wouldn't do it this way but since we want to ensure an
+ equal load balance we do this and then create 4 connections round robined
+
+ final int numMessages = 18;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+
+
+
+
We now consume those messages on *both* server 0 and server 1.
+ We note the messages have been distributed between servers in a round robin fashion.
+ HornetQ has load balanced the messages between the available consumers on the different nodes.
+ HornetQ can be configured to always load balance messages to all nodes, or to only balance messages
+ to nodes which have consumers with no or matching selectors. See the user manual for more details.
+ JMS Queues implement point-to-point message where each message is only ever consumed by a
+ maximum of one consumer.
+
And finally (no pun intended), always remember to close your JMS resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/java/org/hornetq/jms/example/ClusterStaticOnewayExample.java b/examples/jms/clustered-static-oneway/src/main/java/org/hornetq/jms/example/ClusterStaticOnewayExample.java
new file mode 100644
index 0000000000..06b7707139
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/java/org/hornetq/jms/example/ClusterStaticOnewayExample.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple example that demonstrates server side load-balancing of messages between the queue instances on different
+ * nodes of the cluster. The cluster is created from a static list of nodes.
+ *
+ * @author Jeff Mesnil
+ */
+public class ClusterStaticOnewayExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new ClusterStaticOnewayExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection initialConnection = null;
+
+ Connection connection0 = null;
+
+ Connection connection1 = null;
+
+ Connection connection2 = null;
+
+ InitialContext ic0 = null;
+ Thread.sleep(5000);
+ try
+ {
+ // Step 1. Get an initial context for looking up JNDI from server 0
+ ic0 = getContext(0);
+
+ // Step 2. Look-up the JMS Queue object from JNDI
+ Queue queue = (Queue)ic0.lookup("/queue/exampleQueue");
+
+ // Step 3. Look-up a JMS Connection Factory object from JNDI on server 0
+ ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+
+ //step 4. grab an initial connection and wait, in reality you wouldn't do it this way but since we want to ensure an
+ // equal load balance we do this and then create 4 connections round robined
+ initialConnection = cf0.createConnection();
+
+ Thread.sleep(2000);
+ // Step 5. We create a JMS Connection connection0 which is a connection to server 0
+ connection0 = cf0.createConnection();
+
+ // Step 6. We create a JMS Connection connection1 which is a connection to server 1
+ connection1 = cf0.createConnection();
+
+ // Step 7. We create a JMS Connection connection0 which is a connection to server 2
+ connection2 = cf0.createConnection();
+
+ // Step 8. We create a JMS Session on server 0
+ Session session0 = connection0.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 9. We create a JMS Session on server 1
+ Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 10. We create a JMS Session on server 2
+ Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 11. We start the connections to ensure delivery occurs on them
+ connection0.start();
+
+ connection1.start();
+
+ connection2.start();
+
+ // Step 12. We create JMS MessageConsumer objects on server 0,server 1 and server 2
+ MessageConsumer consumer0 = session0.createConsumer(queue);
+
+ MessageConsumer consumer1 = session1.createConsumer(queue);
+
+ MessageConsumer consumer2 = session2.createConsumer(queue);
+
+ Thread.sleep(4000);
+
+ int con0Node = getServer(connection0);
+ int con1Node = getServer(connection1);
+ int con2Node = getServer(connection2);
+
+ System.out.println("con0Node = " + con0Node);
+ System.out.println("con1Node = " + con1Node);
+ System.out.println("con2Node = " + con2Node);
+
+ if(con0Node + con1Node + con2Node != 3)
+ {
+ System.out.println("connections not load balanced");
+ return false;
+ }
+ // Step 13. We create a JMS MessageProducer object on server 0
+ Session sendSession = getServerConnection(0, connection0, connection1, connection2).createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer producer = sendSession.createProducer(queue);
+
+ // Step 14. We send some messages to server 0
+
+ final int numMessages = 18;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+ Thread.sleep(2000);
+ // Step 15. We now consume those messages on *both* server 0,server 1 and 2.
+ // We note the messages have been distributed between servers in a round robin fashion
+ // JMS Queues implement point-to-point message where each message is only ever consumed by a
+ // maximum of one consumer
+
+ for (int i = 0; i < numMessages; i += 3)
+ {
+ TextMessage message0 = (TextMessage)consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node " + con0Node);
+
+ TextMessage message1 = (TextMessage)consumer1.receive(5000);
+
+ System.out.println("Got message: " + message1.getText() + " from node " + con1Node);
+
+ TextMessage message2 = (TextMessage)consumer2.receive(5000);
+
+ System.out.println("Got message: " + message2.getText() + " from node " + con2Node);
+ }
+
+ return true;
+ }
+ finally
+ {
+ // Step 15. Be sure to close our resources!
+
+ if (initialConnection != null)
+ {
+ initialConnection.close();
+ }
+
+ if (connection0 != null)
+ {
+ connection0.close();
+ }
+
+ if (connection1 != null)
+ {
+ connection1.close();
+ }
+
+ if (connection2 != null)
+ {
+ connection2.close();
+ }
+
+ if (ic0 != null)
+ {
+ ic0.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..60b7ef9cb6
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 2
+
+ server1-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..6156e3c2fd
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/jndi.properties b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server0/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-configuration.xml
new file mode 100644
index 0000000000..2109cf2fb5
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-configuration.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+ ${build.directory}/server1/data/messaging/bindings
+
+ ${build.directory}/server1/data/messaging/journal
+
+ ${build.directory}/server1/data/messaging/largemessages
+
+ ${build.directory}/server1/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 2
+
+ server2-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-jms.xml
new file mode 100644
index 0000000000..6156e3c2fd
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-jms.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/jndi.properties b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/jndi.properties
new file mode 100644
index 0000000000..e2a9832f8e
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server1/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-configuration.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-configuration.xml
new file mode 100644
index 0000000000..45d703fc84
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-configuration.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+ ${build.directory}/server2/data/messaging/bindings
+
+ ${build.directory}/server2/data/messaging/journal
+
+ ${build.directory}/server2/data/messaging/largemessages
+
+ ${build.directory}/server2/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-jms.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-jms.xml
new file mode 100644
index 0000000000..abd44d82ea
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-jms.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-users.xml b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/jndi.properties b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/jndi.properties
new file mode 100644
index 0000000000..629072e931
--- /dev/null
+++ b/examples/jms/clustered-static-oneway/src/main/resources/hornetq/server2/jndi.properties
@@ -0,0 +1,15 @@
+#
+# Copyright 2009 Red Hat, Inc.
+# Red Hat 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.
+#
+
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/clustered-topic/pom.xml b/examples/jms/clustered-topic/pom.xml
new file mode 100644
index 0000000000..d5e71a7e8e
--- /dev/null
+++ b/examples/jms/clustered-topic/pom.xml
@@ -0,0 +1,167 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-clustered-topic-example
+ jar
+ HornetQ JMS Clustered Topic Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+ build.directory
+ ${basedir}/target/
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.ClusteredTopicExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-clustered-topic-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/clustered-topic/readme.html b/examples/jms/clustered-topic/readme.html
new file mode 100644
index 0000000000..38c652140c
--- /dev/null
+++ b/examples/jms/clustered-topic/readme.html
@@ -0,0 +1,174 @@
+
+
+ HornetQ JMS Clustered Topic Example
+
+
+
+
+
+
JMS Clustered Topic Example
+
+
This example demonstrates a JMS Topic deployed on two different nodes. The two nodes are configured to form a cluster.
+
We then create a subscriber on the topic on each node, and we create a producer on only one of the nodes.
+
We then send some messages via the producer, and we verify that both subscribers receive all the
+ sent messages.
+
A JMS Topic is an example of publish-subscribe messaging where all subscribers receive all the
+ messages sent to the topic (assuming they have no message selectors).
+
This example uses JNDI to lookup the JMS Queue and ConnectionFactory objects. If you prefer not to use
+ JNDI, these could be instantiated directly.
+
Here's the relevant snippet from the server configuration, which tells the server to form a cluster between the two nodes
+ and to load balance the messages between the nodes.
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+
+
+
+
+ We now consume those messages on both server 0 and server 1.
+ We note that all messages have been consumed by both consumers.
+ JMS Topics implement publish-subscribe messaging where all consumers get a copy of all messages.
+
+
+ for (int i = 0; i < numMessages; i ++)
+ {
+ TextMessage message0 = (TextMessage)consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node 0");
+
+ TextMessage message1 = (TextMessage)consumer1.receive(5000);
+
+ System.out.println("Got message: " + message1.getText() + " from node 1");
+ }
+
+
+
+
And finally (no pun intended), always remember to close your JMS resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/consumer-rate-limit/src/main/java/org/hornetq/jms/example/ConsumerRateLimitExample.java b/examples/jms/consumer-rate-limit/src/main/java/org/hornetq/jms/example/ConsumerRateLimitExample.java
new file mode 100644
index 0000000000..bdbe40cf3a
--- /dev/null
+++ b/examples/jms/consumer-rate-limit/src/main/java/org/hornetq/jms/example/ConsumerRateLimitExample.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * This example demonstrates how a message consumer can be limited to consumer messages at a maximum rate
+ * specified in messages per sec.
+ *
+ * @author Tim Fox
+ */
+public class ConsumerRateLimitExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new ConsumerRateLimitExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4. Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a JMS Message Consumer
+
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ // Step 8. Start the connection
+
+ connection.start();
+
+ // Step 9. Send a bunch of messages
+
+ final int numMessages = 150;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session.createTextMessage("This is text message: " + i);
+
+ producer.send(message);
+ }
+
+ System.out.println("Sent messages");
+
+ System.out.println("Will now try and consume as many as we can in 10 seconds ...");
+
+ // Step 10. Consume as many messages as we can in 10 seconds
+
+ final long duration = 10000;
+
+ int i = 0;
+
+ long start = System.currentTimeMillis();
+
+ while (System.currentTimeMillis() - start <= duration)
+ {
+ TextMessage message = (TextMessage)consumer.receive(2000);
+
+ if (message == null)
+ {
+ return false;
+ }
+
+ i++;
+ }
+
+ long end = System.currentTimeMillis();
+
+ double rate = 1000 * (double)i / (end - start);
+
+ System.out.println("We consumed " + i + " messages in " + (end - start) + " milliseconds");
+
+ System.out.println("Actual consume rate was " + rate + " messages per second");
+
+ return true;
+ }
+ finally
+ {
+ // Step 9. Be sure to close our resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/client-jndi.properties b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/client-jndi.properties
new file mode 100644
index 0000000000..080524fbb8
--- /dev/null
+++ b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/client-jndi.properties
@@ -0,0 +1,3 @@
+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
diff --git a/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-beans.xml b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..171d3739eb
--- /dev/null
+++ b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-beans.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..6307c0e930
--- /dev/null
+++ b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,42 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..a841d0b369
--- /dev/null
+++ b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/consumer-rate-limit/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/dead-letter/pom.xml b/examples/jms/dead-letter/pom.xml
new file mode 100644
index 0000000000..348199ea59
--- /dev/null
+++ b/examples/jms/dead-letter/pom.xml
@@ -0,0 +1,116 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-dead-letter-example
+ jar
+ HornetQ JMS Dead Letter Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.DeadLetterExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-dead-letter-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/dead-letter/readme.html b/examples/jms/dead-letter/readme.html
new file mode 100644
index 0000000000..5856c58eb5
--- /dev/null
+++ b/examples/jms/dead-letter/readme.html
@@ -0,0 +1,207 @@
+
+
+ HornetQ Dead Letter Example
+
+
+
+
+
+
Dead Letter Example
+
+
This example shows you how to define and deal with dead letter messages.
+
Messages can be delivered unsuccessfully (e.g. if the transacted session used to consume them is rolled back).
+ Such a message goes back to the JMS destination ready to be redelivered.
+ However, this means it is possible for a message to be delivered again and again without any success and remain in the destination, clogging the system.
+
To prevent this, messaging systems define dead letter messages: after a specified unsuccessful delivery attempts, the message is removed from the destination
+ and instead routed to a dead letter address where they can be consumed for further investigation.
+
+ The example will show how to configure HornetQ to route a message to a dead letter address after 3 unsuccessful delivery attempts.
+ The example will send 1 message to a queue. We will deliver the message 3 times and rollback the session every time.
+ On the 4th attempt, there won't be any message to consume: it will have been moved to a dead letter address.
+ We will then consume this dead letter message.
+
+
Example setup
+
Dead letter addresses and maximum delivery attempts are defined in the configuration file hornetq-configuration.xml:
This configuration will moved dead letter messages from exampleQueue to the deadLetterQueue.
+
HornetQ allows to specify either a Queue by prefixing the dead-letter-address with jms.queue.
+ or a Topic by prefixing with jms.topic..
+ In this example, we will use a Queue to hold the dead letter messages.
+
The maximum attempts of delivery is 3. Once this figure is reached, a message is considered a dead letter message and is moved to
+ the deadLetterQueue.
+
Since we want to consume messages from this deadLetterQueue, we also need to add a JNDI binding to perform a lookup.
+ This is configured in hornetq-jms.xml
To run the example, simply type mvn verify from this directory
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
Since the queue was configured to move messages to the deadLetterQueue after 3 unsuccessful delivery attempts,
+ the message won't be in the queue anymore
+
+
We try to receive a message from the queue for a 4th. Since there is none, the call will timeout after 5000ms and messageReceived will be null
+
We have configured HornetQ to send any dead letter messages to the deadLetterQueue.
+ We will now consume messages from this queue and receives the dead letter messages.
+
+
We look up the JMS dead letter queue object from JNDI
JMS does not specify the notion of dead letter destinations and messages. From JMS point of view, the message received from the dead letter queue
+ is a different message than the message removed from the queue after the unsuccessful delivery attempts:
+ the messages have the same content (properties and body) but their JMS headers differ.
+ HornetQ defines additional properties for messages received from a dead letter destination
+
+
The message's destination is the dead letter queue
+
+ System.out.println("Destination of the message: " + ((Queue)messageReceived.getJMSDestination()).getQueueName());
+
+
+
The origin destination is stored in the _HQ_ORIG_ADDRESS property
+
+ System.out.println("*Origin destination* of the message: " + messageReceived.getStringProperty("_HQ_ORIG_ADDRESS"));
+
+
+
We do not forget to commit the session to acknowledge that we have received the message from the dead letter queue
+
+ session.commit();
+
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
\ No newline at end of file
diff --git a/examples/jms/dead-letter/src/main/java/org/hornetq/jms/example/DeadLetterExample.java b/examples/jms/dead-letter/src/main/java/org/hornetq/jms/example/DeadLetterExample.java
new file mode 100644
index 0000000000..618958d557
--- /dev/null
+++ b/examples/jms/dead-letter/src/main/java/org/hornetq/jms/example/DeadLetterExample.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * An example showing how messages are moved to dead letter destination when they are unsuccessfully delivered multiple times
+ *
+ * @author Jeff Mesnil
+ *
+ */
+public class DeadLetterExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new DeadLetterExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a * transacted* JMS Session
+ Session session = connection.createSession(true, 0);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("this is a text message");
+
+ // Step 8. Send the Message
+ producer.send(message);
+ System.out.println("Sent message to " + queue.getQueueName() + ": " + message.getText());
+
+ // Step 9. Commit the session to effectively send the message
+ session.commit();
+
+ // Step 10. Create a JMS Message Consumer for the queue
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 11. Start the Connection
+ connection.start();
+
+ // Step 12. We receive a message...
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("1st delivery from " + queue.getQueueName() + ": " + messageReceived.getText());
+
+ // Step 13. ... but we roll back the session. the message returns to the queue ready to be redelivered
+ session.rollback();
+
+ // Step 14. We receive a message and roll back the session a second time
+ messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("2nd delivery from " + queue.getQueueName() + ": " + messageReceived.getText());
+ session.rollback();
+
+ // Step 15. We receive a message and roll back the session a third time
+ messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("3rd delivery from " + queue.getQueueName() + ": " + messageReceived.getText());
+ session.rollback();
+
+ // The message has been delivered unsuccessfully 3 times -> it is moved to the dead letter queue.
+
+ // Step 16. The 4th time, call will timeout after 5000ms and messageReceived will be null
+ messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("4th delivery from " + queue.getQueueName() + ": " + messageReceived);
+
+ // We will now consume the message from the dead letter queue
+
+ // Step 17. Perform a lookup on the dead letter queue
+ Queue deadLetterQueue = (Queue)initialContext.lookup("/queue/deadLetterQueue");
+
+ // Step 18. Create a JMS Message Consumer for the dead letter queue
+ MessageConsumer deadLetterConsumer = session.createConsumer(deadLetterQueue);
+
+ // Step 19. Receive the message from the dead letter queue
+ messageReceived = (TextMessage)deadLetterConsumer.receive(5000);
+
+ // Step 20. The message sent to the queue was moved to the dead letter queue after 3 unsuccessful deliveries
+ System.out.println("Received message from " + deadLetterQueue.getQueueName() +
+ ": " +
+ messageReceived.getText());
+
+ // The message received from the dead letter queue has the same content than the undelivered message but its
+ // JMS headers
+ // differ (from JMS point of view, it's not the same message).
+ // HornetQ defines additional properties for messages received from the dead letter queue
+
+ System.out.println();
+ // Step 21. the messageReceived's destination is now the dead letter queue.
+ System.out.println("Destination of the message: " + ((Queue)messageReceived.getJMSDestination()).getQueueName());
+
+ // Step 22. the *origin* destination is stored in the _HQ_ORIG_ADDRESS property
+ System.out.println("*Origin destination* of the message: " + messageReceived.getStringProperty("_HQ_ORIG_ADDRESS"));
+
+ // Step 23. This time, we commit the session, the delivery from the dead letter queue is successful!
+ session.commit();
+
+ return true;
+ }
+ finally
+ {
+ // Step 24. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/dead-letter/src/main/resources/hornetq/server0/client-jndi.properties b/examples/jms/dead-letter/src/main/resources/hornetq/server0/client-jndi.properties
new file mode 100644
index 0000000000..080524fbb8
--- /dev/null
+++ b/examples/jms/dead-letter/src/main/resources/hornetq/server0/client-jndi.properties
@@ -0,0 +1,3 @@
+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
diff --git a/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-beans.xml b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..cfb2d3e6d1
--- /dev/null
+++ b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-beans.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..b7df0a1da8
--- /dev/null
+++ b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,50 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.deadLetterQueue
+ 3
+
+
+
+
diff --git a/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..48c28dfa99
--- /dev/null
+++ b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/dead-letter/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/delayed-redelivery/pom.xml b/examples/jms/delayed-redelivery/pom.xml
new file mode 100644
index 0000000000..05a2853f30
--- /dev/null
+++ b/examples/jms/delayed-redelivery/pom.xml
@@ -0,0 +1,114 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-delayed-redelivery-example
+ jar
+ HornetQ JMS Delayed Redelivery Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.DelayedRedeliveryExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-delayed-redelivery-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/delayed-redelivery/readme.html b/examples/jms/delayed-redelivery/readme.html
new file mode 100644
index 0000000000..0a2f44d4b6
--- /dev/null
+++ b/examples/jms/delayed-redelivery/readme.html
@@ -0,0 +1,168 @@
+
+
+ HornetQ Delayed Redelivery Example
+
+
+
+
+
+
Delayed Redelivery Example
+
+
This example demonstrates how HornetQ can be configured to provide a delayed redelivery in the case
+ where a message needs to be redelivered.
+
Delaying redelivery can often be useful in the case that clients regularly fail or roll-back. Without a delayed
+ redelivery, the system can get into a "thrashing" state, with delivery being attempted, the client rolling back, and
+ delivery being re-attempted ad infinitum in quick succession, using up valuable CPU and network resources.
+
Re-delivery occurs when the session is closed with unacknowledged messages. The unacknowledged messages will
+ be redelivered.
+
By providing a redelivery delay, it can be specified that a delay of, say, 10 seconds is implemented between rollback
+ and redelivery. The specific delay is configurable on both a global and per destination level, by using wild-card
+ matching on the address settings.
In this example we set the redelivery delay to 5 seconds for the specific example queue. We could set redelivery delay on
+ on multiple queues by specifying a wild-card in the match, e.g. match="jms.#" would apply the settings
+ to all JMS queues and topics.
+
We then consume a message in a transacted session, and rollback, and note that the message is not redelivered until
+ after 5 seconds.
We rollback the session again to cause another redelivery, and we time how long this one takes
+
+
+ long start = System.currentTimeMillis();
+
+ session.rollback();
+
+ messageReceived = (TextMessage)messageConsumer.receive(8000);
+
+ long end = System.currentTimeMillis();
+
+ System.out.println("3nd delivery from " + queue.getQueueName() + ": " + messageReceived.getText() +
+ " after " + (end - start) + " milliseconds.");
+
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
\ No newline at end of file
diff --git a/examples/jms/delayed-redelivery/src/main/java/org/hornetq/jms/example/DelayedRedeliveryExample.java b/examples/jms/delayed-redelivery/src/main/java/org/hornetq/jms/example/DelayedRedeliveryExample.java
new file mode 100644
index 0000000000..097fa47531
--- /dev/null
+++ b/examples/jms/delayed-redelivery/src/main/java/org/hornetq/jms/example/DelayedRedeliveryExample.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * This example demonstrates how HornetQ can be configured with a redelivery delay in the event a message
+ * is redelivered.
+ *
+ * Please see the readme.html for more information
+ *
+ * @author Tim Fox
+ *
+ */
+public class DelayedRedeliveryExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new DelayedRedeliveryExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perform a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4. Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a transacted JMS Session
+ Session session = connection.createSession(true, 0);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("this is a text message");
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ System.out.println("Sent message to " + queue.getQueueName() + ": " + message.getText());
+
+ // Step 9. Commit the session to effectively send the message
+ session.commit();
+
+ // Step 10. Create a JMS Message Consumer for the queue
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 11. Start the Connection
+ connection.start();
+
+ // Step 12. We receive a message...
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("1st delivery from " + queue.getQueueName() + ": " + messageReceived.getText());
+
+ // Step 13. ... but we roll back the session. the message returns to the queue, but only after a
+ // 5 second delay
+ session.rollback();
+
+ // Step 14. We try to receive the message but it's being delayed
+ messageReceived = (TextMessage)messageConsumer.receive(3000);
+
+ if (messageReceived != null)
+ {
+ return false;
+ }
+
+ System.out.println("Redelivery has been delayed so received message is " + messageReceived);
+
+ // Step 15. We try and receive the message again, this time we should get it
+
+ messageReceived = (TextMessage)messageConsumer.receive(3000);
+
+ System.out.println("2nd delivery from " + queue.getQueueName() + ": " + messageReceived.getText());
+
+ // Step 16. We rollback the session again to cause another redelivery, and we time how long this one takes
+
+ long start = System.currentTimeMillis();
+
+ session.rollback();
+
+ messageReceived = (TextMessage)messageConsumer.receive(8000);
+
+ long end = System.currentTimeMillis();
+
+ System.out.println("3nd delivery from " + queue.getQueueName() +
+ ": " +
+ messageReceived.getText() +
+ " after " +
+ (end - start) +
+ " milliseconds.");
+
+ return true;
+ }
+ finally
+ {
+ // Step 17. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/client-jndi.properties b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/client-jndi.properties
new file mode 100644
index 0000000000..080524fbb8
--- /dev/null
+++ b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/client-jndi.properties
@@ -0,0 +1,3 @@
+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
diff --git a/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-beans.xml b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..cfb2d3e6d1
--- /dev/null
+++ b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-beans.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..7251b55b42
--- /dev/null
+++ b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,49 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5000
+
+
+
+
diff --git a/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..48c28dfa99
--- /dev/null
+++ b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/delayed-redelivery/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/divert/pom.xml b/examples/jms/divert/pom.xml
new file mode 100644
index 0000000000..646ffce1c1
--- /dev/null
+++ b/examples/jms/divert/pom.xml
@@ -0,0 +1,152 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-divert-example
+ jar
+ HornetQ JMS Divert Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.DivertExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-divert-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/divert/readme.html b/examples/jms/divert/readme.html
new file mode 100644
index 0000000000..bd7d839e65
--- /dev/null
+++ b/examples/jms/divert/readme.html
@@ -0,0 +1,419 @@
+
+
+ HornetQ Divert Example
+
+
+
+
+
+
Divert Example
+
+
HornetQ diverts allow messages to be transparently "diverted" from one address to another
+ with just some simple configuration defined on the server side.
+
Diverts can be defined to be exclusive or non-exclusive.
+
With an exclusive divert the message is intercepted and does not get sent to the queues originally
+ bound to that address - it only gets diverted.
+
With a non-exclusive divert the message continues to go to the queues bound to the address,
+ but also a copy of the message gets sent to the address specified in the divert. Consequently non-exclusive
+ diverts can be used to "snoop" on another address
+
Diverts can also be configured to have an optional filter. If specified then only matching messages
+ will be diverted.
+
Diverts can be configured to apply a Transformer. If specified, all diverted messages will have the
+ opportunity of being transformed by the Transformer.
+
Diverts are a very sophisticated concept, which when combined with bridges can be used to create
+ interesting and complex routings. The set of diverts can be thought of as a type of routing table
+ for messages.
+
+
Example step-by-step
+
In this example we will imagine a fictitious company which has two offices; one in London and another in New York.
+
The company accepts orders for it's products only at it's London office, and also generates price-updates
+ for it's products, also only from it's London office. However only the New York office is interested in receiving
+ price updates for New York products. Any prices for New York products need to be forwarded to the New York office.
+
There is an unreliable WAN linking the London and New York offices.
+
The company also requires a copy of any order received to be available to be inspected by management.
+
In order to achieve this, we will create a queue orderQueue on the London server in to which orders arrive.
+
We will create a topic, spyTopic on the London server, and there will be two subscribers both in London.
+
We will create a non-exclusive divert on the London server which will siphon off a copy of each order
+ received to the topic spyTopic.
+
Here's the xml config for that divert, from hornetq-configuration.xml
For the prices we will create a topic on the London server, priceUpdates to which all price updates
+ are sent. We will create another topic on the New York server newYorkPriceUpdates to which all New York
+ price updates need to be forwarded.
+
Diverts can only be used to divert messages from one local address to another local address
+ so we cannot divert directly to an address on another server.
+
Instead we divert to a local store and forward queue they we define in the configuration. This is just a normal queue
+ that we use for storing messages before forwarding to another node.
Note we specify a filter in the divert, so only New York prices get diverted. We also specify a Transformer class
+ since we are going to insert a header in the message at divert time, recording the time the diversion happened.
+
And finally we define a bridge that moves messages from the local queue to the address on the New York server.
+ Bridges move messages from queues to remote addresses and are ideal to use when the target server may be stopped and
+ started independently, and/or the network might be unreliable. Bridges guarantee once and only once delivery
+ of messages from their source queues to their target addresses.
Create an initial context to perform the JNDI lookup on the New York server.
+
+
+ initialContextNewYork = getContext(1);
+
+
+
+
Look-up the topic newYorkPriceUpdates on the New York server - any price updates sent to priceUpdates on the London server will
+ be diverted to the queue priceForward on the London server, and a bridge will consume from that queue and forward
+ them to the address newYorkPriceUpdates on the New York server where they will be distributed to the topic subscribers on
+ the New York server.
+
The price update *should not* be received in New York
+
+
+ TextMessage priceUpdate1 = (TextMessage)newYorkPriceUpdatesSubscriberA.receive(1000);
+
+ if (priceUpdate1 != null)
+ {
+ return false;
+ }
+
+ System.out.println("Did not received price update in New York, look it's: " + priceUpdate1);
+
+ TextMessage priceUpdate2 = (TextMessage)newYorkPriceUpdatesSubscriberB.receive(1000);
+
+ if (priceUpdate2 != null)
+ {
+ return false;
+ }
+
+ System.out.println("Did not received price update in New York, look it's: " + priceUpdate2);
+
+
+
+
Create a price update message, destined for New York
+
+
+ TextMessage priceUpdateMessageNewYork = sessionLondon.createTextMessage("This is a price update for New York");
+
+ priceUpdateMessageNewYork.setStringProperty("office", "New York");
+
+
+
+
Send the price update message to the priceUpdates topic on the London server
The price update *should not* be received by the local subscriber to the priceUpdates topic
+ since it has been *exclusively* diverted to the priceForward queue, because it has a header saying
+ it is destined for the New York office
The remote subscribers on server 1 *should* receive a copy of the price update since
+ it has been diverted to a local priceForward queue which has a bridge consuming from it and which
+ forwards it to the same address on server 1.
+ We notice how the forwarded messages have had a special header added by our custom transformer that
+ we told the divert to use
+
+
+ priceUpdate1 = (TextMessage)newYorkPriceUpdatesSubscriberA.receive(5000);
+
+ System.out.println("Received forwarded price update on server 1: " + priceUpdate1.getText());
+ System.out.println("Time of forward: " + priceUpdate1.getLongProperty("time_of_forward"));
+
+ priceUpdate2 = (TextMessage)newYorkPriceUpdatesSubscriberB.receive(5000);
+
+ System.out.println("Received forwarded price update on server 2: " + priceUpdate2.getText());
+ System.out.println("Time of forward: " + priceUpdate2.getLongProperty("time_of_forward"));
+
+
+
+
+
And finally, always remember to close your resources after use, in a finally block.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/divert/src/main/java/org/hornetq/jms/example/AddForwardingTimeTransformer.java b/examples/jms/divert/src/main/java/org/hornetq/jms/example/AddForwardingTimeTransformer.java
new file mode 100644
index 0000000000..ef860f7f3f
--- /dev/null
+++ b/examples/jms/divert/src/main/java/org/hornetq/jms/example/AddForwardingTimeTransformer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import org.hornetq.api.core.SimpleString;
+import org.hornetq.core.server.ServerMessage;
+import org.hornetq.core.server.cluster.Transformer;
+
+/**
+ * A AddForwardingTimeTransformer
+ *
+ * @author Tim Fox
+ *
+ *
+ */
+public class AddForwardingTimeTransformer implements Transformer
+{
+ public ServerMessage transform(final ServerMessage message)
+ {
+ message.putLongProperty(new SimpleString("time_of_forward"), System.currentTimeMillis());
+
+ return message;
+ }
+
+}
diff --git a/examples/jms/divert/src/main/java/org/hornetq/jms/example/DivertExample.java b/examples/jms/divert/src/main/java/org/hornetq/jms/example/DivertExample.java
new file mode 100644
index 0000000000..cd373d6180
--- /dev/null
+++ b/examples/jms/divert/src/main/java/org/hornetq/jms/example/DivertExample.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * This examples demonstrates the use of HornetQ "Diverts" to transparently divert or copy messages
+ * from one address to another.
+ *
+ * Please see the readme.html for more information.
+ *
+ * @author Tim Fox
+ */
+public class DivertExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new DivertExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connectionLondon = null;
+
+ Connection connectionNewYork = null;
+
+ InitialContext initialContextLondon = null;
+
+ InitialContext initialContextNewYork = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup on the London server
+ initialContextLondon = getContext(0);
+
+ // Step 2. Look-up the queue orderQueue on the London server - this is the queue any orders are sent to
+ Queue orderQueue = (Queue)initialContextLondon.lookup("/queue/orders");
+
+ // Step 3. Look-up the topic priceUpdates on the London server- this is the topic that any price updates are
+ // sent to
+ Topic priceUpdates = (Topic)initialContextLondon.lookup("/topic/priceUpdates");
+
+ // Step 4. Look-up the spy topic on the London server- this is what we will use to snoop on any orders
+ Topic spyTopic = (Topic)initialContextLondon.lookup("/topic/spyTopic");
+
+ // Step 6. Create an initial context to perform the JNDI lookup on the New York server
+ initialContextNewYork = getContext(1);
+
+ // Step 7. Look-up the topic newYorkPriceUpdates on the New York server - any price updates sent to
+ // priceUpdates on the London server will
+ // be diverted to the queue priceForward on the London server, and a bridge will consume from that queue and
+ // forward
+ // them to the address newYorkPriceUpdates on the New York server where they will be distributed to the topic
+ // subscribers on
+ // the New York server
+ Topic newYorkPriceUpdates = (Topic)initialContextNewYork.lookup("/topic/newYorkPriceUpdates");
+
+ // Step 8. Perform a lookup on the Connection Factory on the London server
+ ConnectionFactory cfLondon = (ConnectionFactory)initialContextLondon.lookup("/ConnectionFactory");
+
+ // Step 9. Perform a lookup on the Connection Factory on the New York server
+ ConnectionFactory cfNewYork = (ConnectionFactory)initialContextNewYork.lookup("/ConnectionFactory");
+
+ // Step 10. Create a JMS Connection on the London server
+ connectionLondon = cfLondon.createConnection();
+
+ // Step 11. Create a JMS Connection on the New York server
+ connectionNewYork = cfNewYork.createConnection();
+
+ // Step 12. Create a JMS Session on the London server
+ Session sessionLondon = connectionLondon.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 13. Create a JMS Session on the New York server
+ Session sessionNewYork = connectionNewYork.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 14. Create a JMS MessageProducer orderProducer that sends to the queue orderQueue on the London server
+ MessageProducer orderProducer = sessionLondon.createProducer(orderQueue);
+
+ // Step 15. Create a JMS MessageProducer priceProducer that sends to the topic priceUpdates on the London
+ // server
+ MessageProducer priceProducer = sessionLondon.createProducer(priceUpdates);
+
+ // Step 15. Create a JMS subscriber which subscribes to the spyTopic on the London server
+ MessageConsumer spySubscriberA = sessionLondon.createConsumer(spyTopic);
+
+ // Step 16. Create another JMS subscriber which also subscribes to the spyTopic on the London server
+ MessageConsumer spySubscriberB = sessionLondon.createConsumer(spyTopic);
+
+ // Step 17. Create a JMS MessageConsumer which consumes orders from the order queue on the London server
+ MessageConsumer orderConsumer = sessionLondon.createConsumer(orderQueue);
+
+ // Step 18. Create a JMS subscriber which subscribes to the priceUpdates topic on the London server
+ MessageConsumer priceUpdatesSubscriberLondon = sessionLondon.createConsumer(priceUpdates);
+
+ // Step 19. Create a JMS subscriber which subscribes to the newYorkPriceUpdates topic on the New York server
+ MessageConsumer newYorkPriceUpdatesSubscriberA = sessionNewYork.createConsumer(newYorkPriceUpdates);
+
+ // Step 20. Create another JMS subscriber which also subscribes to the newYorkPriceUpdates topic on the New
+ // York server
+ MessageConsumer newYorkPriceUpdatesSubscriberB = sessionNewYork.createConsumer(newYorkPriceUpdates);
+
+ // Step 21. Start the connections
+
+ connectionLondon.start();
+
+ connectionNewYork.start();
+
+ // Step 22. Create an order message
+ TextMessage orderMessage = sessionLondon.createTextMessage("This is an order");
+
+ // Step 23. Send the order message to the order queue on the London server
+ orderProducer.send(orderMessage);
+
+ System.out.println("Sent message: " + orderMessage.getText());
+
+ // Step 24. The order message is consumed by the orderConsumer on the London server
+ TextMessage receivedOrder = (TextMessage)orderConsumer.receive(5000);
+
+ System.out.println("Received order: " + receivedOrder.getText());
+
+ // Step 25. A copy of the order is also received by the spyTopic subscribers on the London server
+ TextMessage spiedOrder1 = (TextMessage)spySubscriberA.receive(5000);
+
+ System.out.println("Snooped on order: " + spiedOrder1.getText());
+
+ TextMessage spiedOrder2 = (TextMessage)spySubscriberB.receive(5000);
+
+ System.out.println("Snooped on order: " + spiedOrder2.getText());
+
+ // Step 26. Create and send a price update message, destined for London
+ TextMessage priceUpdateMessageLondon = sessionLondon.createTextMessage("This is a price update for London");
+
+ priceUpdateMessageLondon.setStringProperty("office", "London");
+
+ priceProducer.send(priceUpdateMessageLondon);
+
+ // Step 27. The price update *should* be received by the local subscriber since we only divert messages
+ // where office = New York
+ TextMessage receivedUpdate = (TextMessage)priceUpdatesSubscriberLondon.receive(2000);
+
+ System.out.println("Received price update locally: " + receivedUpdate.getText());
+
+ // Step 28. The price update *should not* be received in New York
+
+ TextMessage priceUpdate1 = (TextMessage)newYorkPriceUpdatesSubscriberA.receive(1000);
+
+ if (priceUpdate1 != null)
+ {
+ return false;
+ }
+
+ System.out.println("Did not received price update in New York, look it's: " + priceUpdate1);
+
+ TextMessage priceUpdate2 = (TextMessage)newYorkPriceUpdatesSubscriberB.receive(1000);
+
+ if (priceUpdate2 != null)
+ {
+ return false;
+ }
+
+ System.out.println("Did not received price update in New York, look it's: " + priceUpdate2);
+
+ // Step 29. Create a price update message, destined for New York
+
+ TextMessage priceUpdateMessageNewYork = sessionLondon.createTextMessage("This is a price update for New York");
+
+ priceUpdateMessageNewYork.setStringProperty("office", "New York");
+
+ // Step 30. Send the price update message to the priceUpdates topic on the London server
+ priceProducer.send(priceUpdateMessageNewYork);
+
+ // Step 31. The price update *should not* be received by the local subscriber to the priceUpdates topic
+ // since it has been *exclusively* diverted to the priceForward queue, because it has a header saying
+ // it is destined for the New York office
+ Message message = priceUpdatesSubscriberLondon.receive(1000);
+
+ if (message != null)
+ {
+ return false;
+ }
+
+ System.out.println("Didn't receive local price update, look, it's: " + message);
+
+ // Step 32. The remote subscribers on server 1 *should* receive a copy of the price update since
+ // it has been diverted to a local priceForward queue which has a bridge consuming from it and which
+ // forwards it to the same address on server 1.
+ // We notice how the forwarded messages have had a special header added by our custom transformer that
+ // we told the divert to use
+
+ priceUpdate1 = (TextMessage)newYorkPriceUpdatesSubscriberA.receive(5000);
+
+ System.out.println("Received forwarded price update on server 1: " + priceUpdate1.getText());
+ System.out.println("Time of forward: " + priceUpdate1.getLongProperty("time_of_forward"));
+
+ priceUpdate2 = (TextMessage)newYorkPriceUpdatesSubscriberB.receive(5000);
+
+ System.out.println("Received forwarded price update on server 2: " + priceUpdate2.getText());
+ System.out.println("Time of forward: " + priceUpdate2.getLongProperty("time_of_forward"));
+
+ return true;
+ }
+ finally
+ {
+ // Step 12. Be sure to close our resources!
+ if (initialContextLondon != null)
+ {
+ initialContextLondon.close();
+ }
+ if (initialContextNewYork != null)
+ {
+ initialContextNewYork.close();
+ }
+ if (connectionLondon != null)
+ {
+ connectionLondon.close();
+ }
+ if (connectionNewYork != null)
+ {
+ connectionNewYork.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..e963cb2488
--- /dev/null
+++ b/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+ jms.queue.priceForwarding
+
+
+
+
+
+ order-divert
+ jms.queue.orders
+ jms.topic.spyTopic
+ false
+
+
+
+ prices-divert
+ jms.topic.priceUpdates
+ jms.queue.priceForwarding
+
+ org.hornetq.jms.example.AddForwardingTimeTransformer
+ true
+
+
+
+
+
+
+
+ jms.queue.priceForwarding
+ jms.topic.newYorkPriceUpdates
+ -1
+
+ newyork-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..0694025f65
--- /dev/null
+++ b/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/divert/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-configuration.xml
new file mode 100644
index 0000000000..cb7f15a706
--- /dev/null
+++ b/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-configuration.xml
@@ -0,0 +1,45 @@
+
+
+ ${build.directory}/server1/data/messaging/bindings
+
+ ${build.directory}/server1/data/messaging/journal
+
+ ${build.directory}/server1/data/messaging/largemessages
+
+ ${build.directory}/server1/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-jms.xml
new file mode 100644
index 0000000000..9b1bf55e2e
--- /dev/null
+++ b/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-jms.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/divert/src/main/resources/hornetq/server1/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/durable-subscription/pom.xml b/examples/jms/durable-subscription/pom.xml
new file mode 100644
index 0000000000..e4305c1369
--- /dev/null
+++ b/examples/jms/durable-subscription/pom.xml
@@ -0,0 +1,116 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-durable-subscription-example
+ jar
+ HornetQ JMS Durable Subscription Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.DurableSubscriptionExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-durable-subscription-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/durable-subscription/readme.html b/examples/jms/durable-subscription/readme.html
new file mode 100644
index 0000000000..01747346f2
--- /dev/null
+++ b/examples/jms/durable-subscription/readme.html
@@ -0,0 +1,140 @@
+
+
+ HornetQ JMS Durable Subscription Example
+
+
+
+
+
+
JMS Durable Subscription Example
+
+
This example demonstrates how to use a durable subscription with HornetQ.
+
Durable subscriptions are a standard part of JMS, please consult the JMS 1.1 specification for full details.
+
Unlike non durable subscriptions, the key function of durable subscriptions is that the messages contained in them
+ persist longer than the lifetime of the subscriber - i.e. they will accumulate messages sent to the topic even
+ if the subscriber is not currently connected. They will also survive server restarts. Note that for the messages to
+ be persisted, the messages sent to them must be marked as persistent messages.
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
We set the client-id on the connection. This must be the first operation performed on the connection object.
+ The combination of client-id and durable subscription name uniquely identifies the durable subscription. Maybe different durable subscritions can have the same name if they belong to different client-id values
+
+ connection.setClientID("durable-client");
+
+
+
We start the connection. In order for delivery to occur on any consumers or subscribers on a connection, the connection must be started
+
+ connection.start();
+
+
+
We create a JMS session. The session is created as non transacted and will auto acknowledge messages.
We create the durable subscriber on the topic, specifying it's name. Since this is the first time the subscriber is created and a subscription with that name and for this client-id does not already exist, then the underlying durable subscription will be created, and a subscriber will be created and returned for that subscription.
We create and send another text message, message 2, to the same topic
+
+ TextMessage message2 = session.createTextMessage("This is a text message 2");
+
+ messageProducer.send(message2);
+
+
+
Now we close the subscriber. Since the subscription is durable it will continue to survive even though there is no subscriber attached to it. At this point you could even stop and restart the server and the subscription would survive!
+
+
+ subscriber.close();
+
+
+
We now create another durable subscriber, with the same name and same client-id on the same topic. Since the durable subscrition already exists, it will simply return a new subscriber consuming from the same durable subscription instance as before
Now we delete the underlying durable subscription. This will delete any remaining unacknowledged messages in the subscription and a new subscriber will not be able to access them
+
+
+ session.unsubscribe("subscriber-1");
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
diff --git a/examples/jms/durable-subscription/src/main/java/org/hornetq/jms/example/DurableSubscriptionExample.java b/examples/jms/durable-subscription/src/main/java/org/hornetq/jms/example/DurableSubscriptionExample.java
new file mode 100644
index 0000000000..e988284998
--- /dev/null
+++ b/examples/jms/durable-subscription/src/main/java/org/hornetq/jms/example/DurableSubscriptionExample.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple JMS example that shows how to use a durable subscription.
+ *
+ * @author Howard Gao
+ */
+public class DurableSubscriptionExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new DurableSubscriptionExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Look-up the JMS topic
+ Topic topic = (Topic)initialContext.lookup("/topic/exampleTopic");
+
+ // Step 3. Look-up the JMS connection factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4. Create a JMS connection
+ connection = cf.createConnection();
+
+ // Step 5. Set the client-id on the connection
+ connection.setClientID("durable-client");
+
+ // Step 6. Start the connection
+ connection.start();
+
+ // Step 7. Create a JMS session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 8. Create a JMS message producer
+ MessageProducer messageProducer = session.createProducer(topic);
+
+ // Step 9. Create the subscription and the subscriber.
+ TopicSubscriber subscriber = session.createDurableSubscriber(topic, "subscriber-1");
+
+ // Step 10. Create a text message
+ TextMessage message1 = session.createTextMessage("This is a text message 1");
+
+ // Step 11. Send the text message to the topic
+ messageProducer.send(message1);
+
+ System.out.println("Sent message: " + message1.getText());
+
+ // Step 12. Consume the message from the durable subscription
+
+ TextMessage messageReceived = (TextMessage)subscriber.receive();
+
+ System.out.println("Received message: " + messageReceived.getText());
+
+ // Step 13. Create and send another message
+
+ TextMessage message2 = session.createTextMessage("This is a text message 2");
+
+ messageProducer.send(message2);
+
+ System.out.println("Sent message: " + message2.getText());
+
+ // Step 14. Close the subscriber - the server could even be stopped at this point!
+ subscriber.close();
+
+ // Step 15. Create a new subscriber on the *same* durable subscription.
+
+ subscriber = session.createDurableSubscriber(topic, "subscriber-1");
+
+ // Step 16. Consume the message
+
+ messageReceived = (TextMessage)subscriber.receive();
+
+ System.out.println("Received message: " + messageReceived.getText());
+
+ // Step 17. Close the subscriber
+ subscriber.close();
+
+ // Step 18. Delete the durable subscription
+ session.unsubscribe("subscriber-1");
+
+ return true;
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ // Step 19. Be sure to close our JMS resources!
+ connection.close();
+ }
+ if (initialContext != null)
+ {
+ // Step 20. Also close the initialContext!
+ initialContext.close();
+ }
+ }
+ }
+}
diff --git a/examples/jms/durable-subscription/src/main/resources/hornetq/server0/client-jndi.properties b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/client-jndi.properties
new file mode 100644
index 0000000000..080524fbb8
--- /dev/null
+++ b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/client-jndi.properties
@@ -0,0 +1,3 @@
+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
diff --git a/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-beans.xml b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-beans.xml
new file mode 100644
index 0000000000..71274b3809
--- /dev/null
+++ b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-beans.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..575eba5315
--- /dev/null
+++ b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,44 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..f89d475dd9
--- /dev/null
+++ b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/durable-subscription/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/embedded-simple/pom.xml b/examples/jms/embedded-simple/pom.xml
new file mode 100644
index 0000000000..8784f9c4ea
--- /dev/null
+++ b/examples/jms/embedded-simple/pom.xml
@@ -0,0 +1,113 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-embedded-simple-example
+ jar
+ HornetQ JMS Simple Embedded Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.EmbeddedExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-embedded-simple-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/embedded-simple/readme.html b/examples/jms/embedded-simple/readme.html
new file mode 100644
index 0000000000..9ee98d3ea7
--- /dev/null
+++ b/examples/jms/embedded-simple/readme.html
@@ -0,0 +1,52 @@
+
+
+ HornetQ Embedded JMS Server Example
+
+
+
+
+
+
Embedded JMS Server Example
+
+
This examples shows how to setup and run an embedded JMS server using HornetQ along with HornetQ configuration files.
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
Create HornetQ core configuration files and make sure they are within your classpath. By default, HornetQ
+ expects the classnames to be "hornetq-configuration.xml", "hornetq-jms.xml", and "hornetq-users.xml".
+
Create and start HornetQ JMS server
+
+ EmbeddedJMS jmsServer = new EmbeddedJMS();
+ jmsServer.start();
+
+
+
At this point the JMS server is started and any JMS clients can look up JMS resources from the JNDI to send/receive
+ messages from the server. To keep the example simple, we will send and receive a JMS message from the same JVM
+ used to run the JMS server.
See the Queue Example for detailed steps to send and receive a JMS message
+
+
Finally, we stop the JMS server and its associated resources.
+
+
Stop the JMS server
+
+ jmsServer.stop();
+
+
+
Stop the JNDI server
+
+ naming.stop();
+ jndiServer.stop();
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/embedded-simple/src/main/java/org/hornetq/jms/example/EmbeddedExample.java b/examples/jms/embedded-simple/src/main/java/org/hornetq/jms/example/EmbeddedExample.java
new file mode 100644
index 0000000000..50ec94da81
--- /dev/null
+++ b/examples/jms/embedded-simple/src/main/java/org/hornetq/jms/example/EmbeddedExample.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.util.Date;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.hornetq.common.example.HornetQExample;
+import org.hornetq.jms.server.embedded.EmbeddedJMS;
+
+/**
+ * This example demonstrates how to run a HornetQ embedded with JMS
+ *
+ * @author Clebert Suconic
+ * @author Jeff Mesnil
+ */
+public class EmbeddedExample extends HornetQExample
+{
+
+ public static void main(final String[] args) throws Exception
+ {
+ new EmbeddedExample().runExample();
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ try
+ {
+ EmbeddedJMS jmsServer = new EmbeddedJMS();
+ jmsServer.start();
+ System.out.println("Started Embedded JMS Server");
+
+ ConnectionFactory cf = (ConnectionFactory)jmsServer.lookup("ConnectionFactory");
+ Queue queue = (Queue)jmsServer.lookup("/queue/exampleQueue");
+
+ // Step 10. Send and receive a message using JMS API
+ Connection connection = null;
+ try
+ {
+ connection = cf.createConnection();
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer producer = session.createProducer(queue);
+ TextMessage message = session.createTextMessage("Hello sent at " + new Date());
+ System.out.println("Sending message: " + message.getText());
+ producer.send(message);
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+ connection.start();
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(1000);
+ System.out.println("Received message:" + messageReceived.getText());
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ connection.close();
+ }
+
+ // Step 11. Stop the JMS server
+ jmsServer.stop();
+ System.out.println("Stopped the JMS Server");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/examples/jms/embedded-simple/src/main/resources/hornetq-configuration.xml b/examples/jms/embedded-simple/src/main/resources/hornetq-configuration.xml
new file mode 100644
index 0000000000..e05915a17b
--- /dev/null
+++ b/examples/jms/embedded-simple/src/main/resources/hornetq-configuration.xml
@@ -0,0 +1,34 @@
+
+
+ false
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/embedded-simple/src/main/resources/hornetq-jms.xml b/examples/jms/embedded-simple/src/main/resources/hornetq-jms.xml
new file mode 100644
index 0000000000..bc4af35e80
--- /dev/null
+++ b/examples/jms/embedded-simple/src/main/resources/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/embedded-simple/src/main/resources/hornetq-users.xml b/examples/jms/embedded-simple/src/main/resources/hornetq-users.xml
new file mode 100644
index 0000000000..880a9667e7
--- /dev/null
+++ b/examples/jms/embedded-simple/src/main/resources/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/embedded/pom.xml b/examples/jms/embedded/pom.xml
new file mode 100644
index 0000000000..4a2c253e22
--- /dev/null
+++ b/examples/jms/embedded/pom.xml
@@ -0,0 +1,113 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-embedded-example
+ jar
+ HornetQ JMS Embedded Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.EmbeddedExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-embedded-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/embedded/readme.html b/examples/jms/embedded/readme.html
new file mode 100644
index 0000000000..b40b827719
--- /dev/null
+++ b/examples/jms/embedded/readme.html
@@ -0,0 +1,109 @@
+
+
+ HornetQ Embedded JMS Server Example
+
+
+
+
+
+
Embedded JMS Server Example
+
+
This examples shows how to setup and run an embedded JMS server using HornetQ.
+
HornetQ was designed using POJOs (Plain Old Java Objects) which means embedding HornetQ in your own application
+ is as simple as instantiating a few objects.
+
This example does not use any configuration files. The server is configured using POJOs and can be easily ported to any dependency injection framework.
+ We will setup and run a full-fledged JMS server which binds its JMS resources to JNDI and can be accessed by remote clients.
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
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()));
+ Configuration configuration = new ConfigurationImpl();
Start the JMS Server using the HornetQ core server and the JMS configuration
+
+ JMSServerManager jmsServer = new JMSServerManagerImpl(hornetqServer, jmsConfig);
+ jmsServer.start();
+
+
+
At this point the JMS server is started and any JMS clients can look up JMS resources from JNDI to send/receive
+ messages from the server. To keep the example simple, we will send and receive a JMS message from the same JVM
+ used to run the JMS server.
See the Queue Example for detailed steps to send and receive a JMS message
+
+
Finally, we stop the JMS server and its associated resources.
+
+
Stop the JMS server
+
+ jmsServer.stop();
+
+
+
Stop the JNDI server
+
+ naming.stop();
+ jndiServer.stop();
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/embedded/src/main/java/org/hornetq/jms/example/EmbeddedExample.java b/examples/jms/embedded/src/main/java/org/hornetq/jms/example/EmbeddedExample.java
new file mode 100644
index 0000000000..79b9de35da
--- /dev/null
+++ b/examples/jms/embedded/src/main/java/org/hornetq/jms/example/EmbeddedExample.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.common.example.HornetQExample;
+import org.hornetq.core.config.Configuration;
+import org.hornetq.core.config.impl.ConfigurationImpl;
+import org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.jms.server.config.ConnectionFactoryConfiguration;
+import org.hornetq.jms.server.config.JMSConfiguration;
+import org.hornetq.jms.server.config.JMSQueueConfiguration;
+import org.hornetq.jms.server.config.impl.ConnectionFactoryConfigurationImpl;
+import org.hornetq.jms.server.config.impl.JMSConfigurationImpl;
+import org.hornetq.jms.server.config.impl.JMSQueueConfigurationImpl;
+import org.hornetq.jms.server.embedded.EmbeddedJMS;
+
+/**
+ * This example demonstrates how to run a HornetQ embedded with JMS
+ *
+ * @author Clebert Suconic
+ * @author Jeff Mesnil
+ * @author Bill Burke
+ */
+public final class EmbeddedExample extends HornetQExample
+{
+
+ public static void main(final String[] args) throws Exception
+ {
+ new EmbeddedExample().runExample();
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ try
+ {
+
+ // Step 1. Create HornetQ core configuration, and set the properties accordingly
+ Configuration configuration = new ConfigurationImpl();
+ configuration.setPersistenceEnabled(false);
+ configuration.setJournalDirectory("target/data/journal");
+ configuration.setSecurityEnabled(false);
+ configuration.getAcceptorConfigurations()
+ .add(new TransportConfiguration(NettyAcceptorFactory.class.getName()));
+
+ TransportConfiguration connectorConfig = new TransportConfiguration(NettyConnectorFactory.class.getName());
+
+ configuration.getConnectorConfigurations().put("connector", connectorConfig);
+
+
+ // Step 2. Create the JMS configuration
+ JMSConfiguration jmsConfig = new JMSConfigurationImpl();
+
+ // Step 3. Configure the JMS ConnectionFactory
+ ArrayList connectorNames = new ArrayList();
+ connectorNames.add("connector");
+ ConnectionFactoryConfiguration cfConfig = new ConnectionFactoryConfigurationImpl("cf", false, connectorNames, "/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();
+ System.out.println("Started Embedded JMS Server");
+
+ // Step 6. Lookup JMS resources defined in the configuration
+ ConnectionFactory cf = (ConnectionFactory)jmsServer.lookup("/cf");
+ Queue queue = (Queue)jmsServer.lookup("/queue/queue1");
+
+ // Step 7. Send and receive a message using JMS API
+ Connection connection = null;
+ try
+ {
+ connection = cf.createConnection();
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer producer = session.createProducer(queue);
+ TextMessage message = session.createTextMessage("Hello sent at " + new Date());
+ System.out.println("Sending message: " + message.getText());
+ producer.send(message);
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+ connection.start();
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(1000);
+ System.out.println("Received message:" + messageReceived.getText());
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ connection.close();
+ }
+
+ // Step 11. Stop the JMS server
+ jmsServer.stop();
+ System.out.println("Stopped the JMS Server");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/examples/jms/expiry/pom.xml b/examples/jms/expiry/pom.xml
new file mode 100644
index 0000000000..de4467def5
--- /dev/null
+++ b/examples/jms/expiry/pom.xml
@@ -0,0 +1,116 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-expiry-example
+ jar
+ HornetQ JMS Expiry Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.ExpiryExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-expiry-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/expiry/readme.html b/examples/jms/expiry/readme.html
new file mode 100644
index 0000000000..df2f2faa2b
--- /dev/null
+++ b/examples/jms/expiry/readme.html
@@ -0,0 +1,187 @@
+
+
+ HornetQ Message Expiration Example
+
+
+
+
+
+
JMS Expiration Example
+
+
This example shows you how to configure HornetQ so messages are expipired after a certain time..
+
Messages can be retained in the messaging system for a limited period of time before being removed.
+ JMS specification states that clients should not receive messages that have been expired (but it does not guarantee this will not happen).
+
HornetQ can assign a expiry address to a given queue so that when messages are expired, they are removed from the queue and
+ routed to an this address. These "expired" messages can later be consumed for further inspection.
+
+ The example will send 1 message with a short time-to-live to a queue. We will wait for the message to expire and checks that the message
+ is no longer in the queue it was sent to.
+ We will instead consume it from an expiry queue where it was moved when it expired.
+
This configuration will moved expired messages from the exampleQueue to the expiryQueue
+
HornetQ allows to specify either a Queue by prefixing the expiry-address with jms.queue.
+ or a Topic by prefixing with jms.topic..
+ In this example, we will use a Queue to hold the expired messages.
+
Since we want to consume messages from this expiryQueue, we also need to add a JNDI binding to perform a lookup.
+ This is configured in hornetq-jms.xml
To run the example, simply type mvn verify from this directory
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
However, we have configured HornetQ to send any expired messages to the expiryQueue.
+ We will now consume messages from this expiry queue and receives the expired message.
JMS does not specify the notion of expiry queue. From JMS point of view, the message received from the expiry queue
+ is a different message than the message expired from the queue: the two messages have the same content (properties and body) but
+ their JMS headers differ.
+ HornetQ defines additional properties to correlate the message received from the expiry queue with the
+ message expired from the queue
+
+
The expired message's destination is the expiry queue
+
+ System.out.println("Destination of the expired message: " + ((Queue)messageReceived.getJMSDestination()).getQueueName());
+
+
+
The expired message has its own expiration time (its time to live in the expiry queue)
+
+ System.out.println("Expiration time of the expired message (relative to the expiry queue): " + messageReceived.getJMSExpiration());
+
+
+
As we have not defined a time-to-live for the expiry queue, messages sent to the expiry queue will be kept forever (their JMS Expiration value is 0)
+
+
The origin destination is stored in the _HORNETQ_ORIG_DESTINATION property
+
+ System.out.println("*Origin destination* of the expired message: " + messageReceived.getStringProperty("_HORNETQ_ORIG_DESTINATION"));
+
+
+
The actual expiration time (when the message was expired from the queue) is stored in the _HORNETQ_ACTUAL_EXPIRY property
+
+ System.out.println("*Actual expiration time* of the expired message: " + messageReceived.getLongProperty("_HORNETQ_ACTUAL_EXPIRY"));
+
+
+
+
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
\ No newline at end of file
diff --git a/examples/jms/expiry/src/main/java/org/hornetq/jms/example/ExpiryExample.java b/examples/jms/expiry/src/main/java/org/hornetq/jms/example/ExpiryExample.java
new file mode 100644
index 0000000000..a58fe71ff4
--- /dev/null
+++ b/examples/jms/expiry/src/main/java/org/hornetq/jms/example/ExpiryExample.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * An example showing how messages are moved to an expiry queue when they expire.
+ *
+ * @author Jeff Mesnil
+ *
+ */
+public class ExpiryExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new ExpiryExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Messages sent by this producer will be retained for 1s (1000ms) before expiration
+ producer.setTimeToLive(1000);
+
+ // Step 8. Create a Text Message
+ TextMessage message = session.createTextMessage("this is a text message");
+
+ // Step 9. Send the Message
+ producer.send(message);
+ System.out.println("Sent message to " + queue.getQueueName() + ": " + message.getText());
+
+ // Step 10. Sleep for 5s. Once we wake up, the message will have been expired
+ System.out.println("Sleep a little bit to let the message expire...");
+ Thread.sleep(5000);
+
+ // Step 11. Create a JMS Message Consumer for the queue
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 12. Start the Connection
+ connection.start();
+
+ // Step 13. Trying to receive a message. Since there is none on the queue, the call will timeout after 5000ms
+ // and messageReceived will be null
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+ System.out.println("Received message from " + queue.getQueueName() + ": " + messageReceived);
+
+ // Step 14. Perfom a lookup on the expiry queue
+ Queue expiryQueue = (Queue)initialContext.lookup("/queue/expiryQueue");
+
+ // Step 15. Create a JMS Message Consumer for the expiry queue
+ MessageConsumer expiryConsumer = session.createConsumer(expiryQueue);
+
+ // Step 16. Receive the message from the expiry queue
+ messageReceived = (TextMessage)expiryConsumer.receive(5000);
+
+ // Step 17. The message sent to the queue was moved to the expiry queue when it expired.
+ System.out.println("Received message from " + expiryQueue.getQueueName() + ": " + messageReceived.getText());
+
+ // The message received from the expiry queue has the same content than the expired message but its JMS headers
+ // differ
+ // (from JMS point of view, it's not the same message).
+ // HornetQ defines additional properties to correlate the message received from the expiry queue with the
+ // message expired from the queue
+
+ System.out.println();
+ // Step 18. the messageReceived's destination is now the expiry queue.
+ System.out.println("Destination of the expired message: " + ((Queue)messageReceived.getJMSDestination()).getQueueName());
+ // Step 19. and its own expiration (the time to live in the *expiry* queue)
+ System.out.println("Expiration time of the expired message (relative to the expiry queue): " + messageReceived.getJMSExpiration());
+
+ System.out.println();
+ // Step 20. the *origin* destination is stored in the _HQ_ORIG_ADDRESS property
+ System.out.println("*Origin destination* of the expired message: " + messageReceived.getStringProperty("_HQ_ORIG_ADDRESS"));
+ // Step 21. the actual expiration time is stored in the _HQ_ACTUAL_EXPIRY property
+ System.out.println("*Actual expiration time* of the expired message: " + messageReceived.getLongProperty("_HQ_ACTUAL_EXPIRY"));
+
+ return true;
+ }
+ finally
+ {
+ // Step 22. Be sure to close the resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..cd87fa9ef5
--- /dev/null
+++ b/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,50 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jms.queue.expiryQueue
+
+
+
+
diff --git a/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..417a5a2649
--- /dev/null
+++ b/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/expiry/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/ha-policy-autobackup/pom.xml b/examples/jms/ha-policy-autobackup/pom.xml
new file mode 100644
index 0000000000..f9f61ce3cc
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/pom.xml
@@ -0,0 +1,153 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ ha-policy-autobackup
+ jar
+ HornetQ JMS HA Policy Auto backup example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+ udp-address
+ ${udp-address}
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.HAPolicyAutoBackupExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+
+
+ org.hornetq.examples.jms
+ ha-policy-autobackup
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/ha-policy-autobackup/src/main/java/org/hornetq/jms/example/HAPolicyAutoBackupExample.java b/examples/jms/ha-policy-autobackup/src/main/java/org/hornetq/jms/example/HAPolicyAutoBackupExample.java
new file mode 100644
index 0000000000..1931956c8e
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/java/org/hornetq/jms/example/HAPolicyAutoBackupExample.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClusterTopologyListener;
+import org.hornetq.api.core.client.TopologyMember;
+import org.hornetq.common.example.HornetQExample;
+import org.hornetq.jms.client.HornetQConnection;
+import org.hornetq.jms.client.HornetQConnectionFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A simple example that demonstrates server side load-balancing of messages between the queue instances on different
+ * nodes of the cluster.
+ *
+ */
+public class HAPolicyAutoBackupExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new HAPolicyAutoBackupExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection0 = null;
+
+ Connection connection1 = null;
+
+ InitialContext ic0 = null;
+
+ InitialContext ic1 = null;
+
+ try
+ {
+ // Step 1. Get an initial context for looking up JNDI from server 0 and 1
+ ic0 = getContext(0);
+ ic1 = getContext(1);
+
+ // Step 2. Look-up the JMS Queue object from JNDI
+ Queue queue = (Queue) ic0.lookup("/queue/exampleQueue");
+
+ // Step 3. Look-up a JMS Connection Factory object from JNDI on server 0 and 1
+ ConnectionFactory cf0 = (ConnectionFactory) ic0.lookup("/ConnectionFactory");
+ ConnectionFactory cf1 = (ConnectionFactory) ic1.lookup("/ConnectionFactory");
+
+ // Step 6. We create JMS Connections to server 0 and 1
+ connection0 = cf0.createConnection();
+ connection1 = cf1.createConnection();
+
+ // step 7. wait for the backups to start replication
+ waitForBackups(cf0, 2);
+
+ // Step 8. We create JMS Sessions on server 0 and 1
+ Session session0 = connection0.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 9. We start the connections to ensure delivery occurs on them
+ connection0.start();
+ connection1.start();
+
+ // Step 10. We create JMS MessageConsumer objects on server 0 and server 1
+ MessageConsumer consumer0 = session0.createConsumer(queue);
+ MessageConsumer consumer1 = session1.createConsumer(queue);
+
+
+ // Step 11. We create a JMS MessageProducer object on server 0
+ MessageProducer producer = session0.createProducer(queue);
+
+ // Step 12. We send some messages to server 0
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ TextMessage message = session0.createTextMessage("This is text message " + i);
+
+ producer.send(message);
+
+ System.out.println("Sent message: " + message.getText());
+ }
+
+ // Step 13. We now consume half the messages on consumer0
+ // note that the other half of the messages will have been sent to server1 for consumer1
+ for (int i = 0; i < numMessages / 2; i++)
+ {
+ TextMessage message0 = (TextMessage) consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node 0");
+ }
+
+ // Step 14.now kill server1, messages will be scaled down to server0
+ killServer(1);
+
+ // Step 15.close the consumer so it doesnt get any messages
+ consumer1.close();
+
+ // Step 16. we now receive the messages that were on server1 but were scaled down to server0
+ for (int i = 0; i < numMessages / 2; i++)
+ {
+ TextMessage message0 = (TextMessage) consumer0.receive(5000);
+
+ System.out.println("Got message: " + message0.getText() + " from node 1");
+ }
+
+ return true;
+ }
+ finally
+ {
+ // Step 17. Be sure to close our resources!
+
+ if (connection0 != null)
+ {
+ connection0.close();
+ }
+
+ if (connection1 != null)
+ {
+ connection1.close();
+ }
+ }
+ }
+
+ private void waitForBackups(ConnectionFactory cf0, int backups) throws InterruptedException
+ {
+ final CountDownLatch latch = new CountDownLatch(backups);
+ ((HornetQConnectionFactory) cf0).getServerLocator().addClusterTopologyListener(new ClusterTopologyListener()
+ {
+ List backups = new ArrayList();
+ @Override
+ public void nodeUP(TopologyMember member, boolean last)
+ {
+ if (member.getBackup() != null && !backups.contains(member.getBackup()))
+ {
+ backups.add(member.getBackup());
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void nodeDown(long eventUID, String nodeID)
+ {
+ }
+ });
+ latch.await(30000, TimeUnit.MILLISECONDS);
+ }
+
+}
diff --git a/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..6c90184e7e
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,82 @@
+
+
+ target/server0/data/messaging/bindings
+
+ target/server0/data/messaging/journal
+
+ target/server0/data/messaging/largemessages
+
+ target/server0/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ 1
+
+ invm-connector
+
+
+ invm-connector
+ server1-connector
+ netty-connector
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+ server1-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..50eb1365d2
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-configuration.xml
new file mode 100644
index 0000000000..36b3d9d55c
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-configuration.xml
@@ -0,0 +1,82 @@
+
+
+ target/server1/data/messaging/bindings
+
+ target/server1/data/messaging/journal
+
+ target/server1/data/messaging/largemessages
+
+ target/server1/data/messaging/paging
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+ 1
+
+ invm-connector
+
+
+ invm-connector
+ server0-connector
+ netty-connector
+
+
+
+
+
+ jms
+ netty-connector
+ 500
+ true
+ true
+ 1
+
+ server0-connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-jms.xml
new file mode 100644
index 0000000000..50eb1365d2
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-jms.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+ true
+
+ 1000
+
+
+ 1.0
+
+
+ -1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/ha-policy-autobackup/src/main/resources/hornetq/server1/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/hornetq-jms-examples-common/common.css b/examples/jms/hornetq-jms-examples-common/common.css
new file mode 100644
index 0000000000..333ea01bfd
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/common.css
@@ -0,0 +1,29 @@
+body {
+ background: url(images/hornetQ-banner_final.png) top left no-repeat;
+}
+
+h1 {
+ margin-top: 110px;
+ font-size: 250%;
+}
+
+code {
+ background-color: lightgrey;
+ color:#333;
+}
+
+pre {
+ background-color: lightgrey;
+ display:block;
+ overflow:auto;
+ border: dotted grey 1px;
+}
+
+abbr {
+ border-bottom: 1px dotted #333; cursor: help;
+}
+
+.missing-doc {
+ background-color: red;
+ border: dotted black 1px;
+}
diff --git a/examples/jms/hornetq-jms-examples-common/config/hornetq-example-beans.xml b/examples/jms/hornetq-jms-examples-common/config/hornetq-example-beans.xml
new file mode 100644
index 0000000000..e70555a435
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/config/hornetq-example-beans.xml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1099
+ localhost
+ 1098
+ localhost
+
+
+
+
+
+ 5000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AddressSettingsDeployer
+ QueueDeployer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/hornetq-jms-examples-common/config/logging.properties b/examples/jms/hornetq-jms-examples-common/config/logging.properties
new file mode 100644
index 0000000000..85e6088f42
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/config/logging.properties
@@ -0,0 +1,35 @@
+############################################################
+# Default Logging Configuration File
+#
+# You can use a different file by specifying a filename
+# with the java.util.logging.config.file system property.
+# For example java -Djava.util.logging.config.file=myfile
+############################################################
+
+############################################################
+# Global properties
+############################################################
+
+# "handlers" specifies a comma separated list of log Handler
+# classes. These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# By default we only configure a ConsoleHandler, which will only
+# show messages at the INFO and above levels.
+handlers=java.util.logging.ConsoleHandler
+#handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
+java.util.logging.ConsoleHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+java.util.logging.FileHandler.level=INFO
+java.util.logging.FileHandler.formatter=org.hornetq.integration.logging.HornetQLoggerFormatter
+java.util.logging.FileHandler.pattern=logs/hornetq.log
+# Default global logging level.
+# This specifies which kinds of events are logged across
+# all loggers. For any given facility this global level
+# can be overriden by a facility specific level
+# Note that the ConsoleHandler also has a separate level
+# setting to limit messages printed to the console.
+.level= INFO
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
diff --git a/examples/jms/hornetq-jms-examples-common/config/server.properties b/examples/jms/hornetq-jms-examples-common/config/server.properties
new file mode 100644
index 0000000000..0388e87151
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/config/server.properties
@@ -0,0 +1 @@
+server.args=-XX:+UseParallelGC -Xms256M -Xmx256M -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -Dcom.sun.management.jmxremote -Djava.util.logging.config.file=${imported.basedir}/config/logging.properties -Djava.naming.factory.initial=org.jnp.interfaces.NamingContextFactory -Djava.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/examples/jms/hornetq-jms-examples-common/images/hornetQ-banner_final.png b/examples/jms/hornetq-jms-examples-common/images/hornetQ-banner_final.png
new file mode 100644
index 0000000000..6388dff1f5
Binary files /dev/null and b/examples/jms/hornetq-jms-examples-common/images/hornetQ-banner_final.png differ
diff --git a/examples/jms/hornetq-jms-examples-common/pom.xml b/examples/jms/hornetq-jms-examples-common/pom.xml
new file mode 100644
index 0000000000..90e28a3e9c
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-examples-common
+ jar
+ HornetQ Examples common
+
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+ org.hornetq
+ hornetq-commons
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/hornetq-jms-examples-common/prettify.css b/examples/jms/hornetq-jms-examples-common/prettify.css
new file mode 100755
index 0000000000..0f1ed75995
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/prettify.css
@@ -0,0 +1 @@
+.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun{color:#660}.pln{color:#000}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec{color:#606}pre.prettyprint{padding:2px;border:1px solid #888}@media print{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun{color:#440}.pln{color:#000}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}
\ No newline at end of file
diff --git a/examples/jms/hornetq-jms-examples-common/prettify.js b/examples/jms/hornetq-jms-examples-common/prettify.js
new file mode 100755
index 0000000000..8fc4c93393
--- /dev/null
+++ b/examples/jms/hornetq-jms-examples-common/prettify.js
@@ -0,0 +1,23 @@
+function H(){var x=navigator&&navigator.userAgent&&/\bMSIE 6\./.test(navigator.userAgent);H=function(){return x};return x}(function(){function x(b){b=b.split(/ /g);var a={};for(var c=b.length;--c>=0;){var d=b[c];if(d)a[d]=null}return a}var y="break continue do else for if return while ",U=y+"auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile ",D=U+"catch class delete false import new operator private protected public this throw true try ",
+I=D+"alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where ",J=D+"boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient ",V=J+"as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var ",
+K=D+"debugger eval export function get null set undefined var with Infinity NaN ",L="caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END ",M=y+"and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None ",N=y+"alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END ",
+O=y+"case done elif esac eval fi function in local set then until ",W=I+V+K+L+M+N+O;function X(b){return b>="a"&&b<="z"||b>="A"&&b<="Z"}function u(b,a,c,d){b.unshift(c,d||0);try{a.splice.apply(a,b)}finally{b.splice(0,2)}}var Y=(function(){var b=["!","!=","!==","#","%","%=","&","&&","&&=","&=","(","*","*=","+=",",","-=","->","/","/=",":","::",";","<","<<","<<=","<=","=","==","===",">",">=",">>",">>=",">>>",">>>=","?","@","[","^","^=","^^","^^=","{","|","|=","||","||=","~","break","case","continue",
+"delete","do","else","finally","instanceof","return","throw","try","typeof"],a="(?:(?:(?:^|[^0-9.])\\.{1,3})|(?:(?:^|[^\\+])\\+)|(?:(?:^|[^\\-])-)";for(var c=0;c:&])/g,"\\$1")}a+="|^)\\s*$";return new RegExp(a)})(),P=/&/g,Q=//g,Z=/\"/g;function $(b){return b.replace(P,"&").replace(Q,"<").replace(R,">").replace(Z,""")}function E(b){return b.replace(P,"&").replace(Q,"<").replace(R,">")}var aa=
+/</g,ba=/>/g,ca=/'/g,da=/"/g,ea=/&/g,fa=/ /g;function ga(b){var a=b.indexOf("&");if(a<0)return b;for(--a;(a=b.indexOf("",a+1))>=0;){var c=b.indexOf(";",a);if(c>=0){var d=b.substring(a+3,c),g=10;if(d&&d.charAt(0)==="x"){d=d.substring(1);g=16}var e=parseInt(d,g);if(!isNaN(e))b=b.substring(0,a)+String.fromCharCode(e)+b.substring(c+1)}}return b.replace(aa,"<").replace(ba,">").replace(ca,"'").replace(da,'"').replace(ea,"&").replace(fa," ")}function S(b){return"XMP"===b.tagName}
+function z(b,a){switch(b.nodeType){case 1:var c=b.tagName.toLowerCase();a.push("<",c);for(var d=0;d");for(var e=b.firstChild;e;e=e.nextSibling)z(e,a);if(b.firstChild||!/^(?:br|link|img)$/.test(c))a.push("",c,">");break;case 2:a.push(b.name.toLowerCase(),'="',$(b.value),'"');break;case 3:case 4:a.push(E(b.nodeValue));break}}var F=null;function ha(b){if(null===F){var a=document.createElement("PRE");
+a.appendChild(document.createTextNode('\n'));F=!/=0;i-=" ".length)d.push(" ".substring(0,i));g=e+1;break;
+case "\n":a=0;break;default:++a}}if(!d)return c;d.push(c.substring(g));return d.join("")}}var ja=/(?:[^<]+|
+
+
+
+ HornetQ 2.0 Resource Adapter
+ HornetQ 2.0 Resource Adapter
+
+ Red Hat Middleware LLC
+ JMS 1.1 Server
+ 1.0
+
+
+
+Copyright 2009 Red Hat, Inc.
+ Red Hat 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.
+
+ true
+
+
+
+ org.hornetq.ra.HornetQResourceAdapter
+
+
+ The transport type. Multiple connectors can be configured by using a comma separated list,
+ i.e. org.hornetq.core.remoting.impl.invm.InVMConnectorFactory,org.hornetq.core.remoting.impl.invm.InVMConnectorFactory.
+
+ ConnectorClassName
+ java.lang.String
+ org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+
+
+ The transport configuration. These values must be in the form of key=val;key=val;,
+ if multiple connectors are used then each set must be separated by a comma i.e. host=host1;port=5445,host=host2;port=5446.
+ Each set of params maps to the connector classname specified.
+
+ ConnectionParameters
+ java.lang.String
+ server-id=0
+
+
+
+
+
+ org.hornetq.ra.HornetQRAManagedConnectionFactory
+
+
+ The default session type
+ SessionDefaultType
+ java.lang.String
+ javax.jms.Queue
+
+
+ Try to obtain a lock within specified number of seconds; less than or equal to 0 disable this functionality
+ UseTryLock
+ java.lang.Integer
+ 0
+
+
+ org.hornetq.ra.HornetQRAConnectionFactory
+ org.hornetq.ra.HornetQRAConnectionFactoryImpl
+ javax.jms.Session
+ org.hornetq.ra.HornetQRASession
+
+ XATransaction
+
+ BasicPassword
+ javax.resource.spi.security.PasswordCredential
+
+ false
+
+
+
+
+
+ javax.jms.MessageListener
+
+ org.hornetq.ra.inflow.HornetQActivationSpec
+
+ destination
+
+
+
+
+
+
+
+
diff --git a/examples/jms/http-transport/pom.xml b/examples/jms/http-transport/pom.xml
new file mode 100644
index 0000000000..b8a500b999
--- /dev/null
+++ b/examples/jms/http-transport/pom.xml
@@ -0,0 +1,122 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-http-transport-example
+ jar
+ HornetQ JMS Http Transport Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.HttpTransportExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-http-transport-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/http-transport/readme.html b/examples/jms/http-transport/readme.html
new file mode 100644
index 0000000000..a71937c57e
--- /dev/null
+++ b/examples/jms/http-transport/readme.html
@@ -0,0 +1,115 @@
+
+
+ HornetQ JMS HTTP Transport Example
+
+
+
+
+
+
JMS HTTP Example
+
+
This example shows you how to configure HornetQ to use the HTTP protocol as its transport layer.
+
+
HornetQ supports a variety of network protocols to be its underlying transport without any specific code change.
+
+
This example is taken from the queue example without any code change. By changing the configuration file, one can get HornetQ working with HTTP transport.
+
All you need to do is open the server0/hornetq-configuration.xml and enable HTTP like the following
To run the example, simply type mvn verify from this directory
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
diff --git a/examples/jms/http-transport/src/main/java/org/hornetq/jms/example/HttpTransportExample.java b/examples/jms/http-transport/src/main/java/org/hornetq/jms/example/HttpTransportExample.java
new file mode 100644
index 0000000000..02e895e41f
--- /dev/null
+++ b/examples/jms/http-transport/src/main/java/org/hornetq/jms/example/HttpTransportExample.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple JMS Queue example that uses HTTP protocol.
+ *
+ * @author Howard Gao
+ */
+public class HttpTransportExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new HttpTransportExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ System.out.println("connection created: " + connection);
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9. Create a JMS Message Consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 10. Start the Connection
+ connection.start();
+
+ // Step 11. Receive the message
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+
+ System.out.println("Received message: " + messageReceived.getText());
+
+ initialContext.close();
+
+ return true;
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..8f13ec84f2
--- /dev/null
+++ b/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,46 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..678e7f5214
--- /dev/null
+++ b/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/http-transport/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/instantiate-connection-factory/pom.xml b/examples/jms/instantiate-connection-factory/pom.xml
new file mode 100644
index 0000000000..5c078db72b
--- /dev/null
+++ b/examples/jms/instantiate-connection-factory/pom.xml
@@ -0,0 +1,126 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-instantiate-connection-factory-example
+ jar
+ HornetQ JMS Instantiate Connection Factory Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.InstantiateConnectionFactoryExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-instantiate-connection-factory-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/instantiate-connection-factory/readme.html b/examples/jms/instantiate-connection-factory/readme.html
new file mode 100644
index 0000000000..59f63dbda7
--- /dev/null
+++ b/examples/jms/instantiate-connection-factory/readme.html
@@ -0,0 +1,118 @@
+
+
+ HornetQ JMS Instantiate Connection Factory Example
+
+
+
+
+
+
JMS Instantiate Connection Factory Example
+
+
Usually, JMS Objects such as ConnectionFactories, Queue and Topic instances are looked up from JNDI
+ before being used by the client code. This objects are called "administered objects" in JMS specification
+ terminology.
+
However, in some cases a JNDI server may not be available or desired. To come to the rescue HornetQ
+ also supports the direct instantiation of these administered objects on the client side.
+
This allows the full set of JMS functionality to be available without requiring a JNDI server!
+
This example is very simple and based on the simple Queue example, however in this example we
+ instantiate the JMS Queue and ConnectionFactory objects directly.
+
A wide variety of methods are available for instantiating ConnectionFactory objects. In this example
+ we use a simple method which just takes the server connection details so it knows where to make the
+ connection to.
+
Other methods are available so all the connection factory parameters can be specified
+ including specifying UDP discovery so the client does not need hard-wired knowledge of where the servers
+ are that it wishes to connect to, or for specifying live-backup pairs of servers for failover.
+
For more information on instantiating ConnectionFactories directly please consult the user manual and
+ javadoc.
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
Instead of looking it up from JNDI we directly instantiate the JMS Queue object. We
+ pass in the name of the JMS Queue in the constructor. The actual JMS Queue must already be deployed on
+ the server.
+
+
+ Queue queue = new HornetQQueue("exampleQueue");
+
+
+
Instantiate the TransportConfiguration object. The TransportConfiguration instance encapsulates
+ the connection details of the server we're connecting to. In this case we're using Netty as a transport, and
+ we're specifying to connect on port 5446.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/instantiate-connection-factory/src/main/java/org/hornetq/jms/example/InstantiateConnectionFactoryExample.java b/examples/jms/instantiate-connection-factory/src/main/java/org/hornetq/jms/example/InstantiateConnectionFactoryExample.java
new file mode 100644
index 0000000000..f5c722ec17
--- /dev/null
+++ b/examples/jms/instantiate-connection-factory/src/main/java/org/hornetq/jms/example/InstantiateConnectionFactoryExample.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.jms.HornetQJMSClient;
+import org.hornetq.api.jms.JMSFactoryType;
+import org.hornetq.common.example.HornetQExample;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.core.remoting.impl.netty.TransportConstants;
+
+/**
+ *
+ * This example demonstrates how a JMS client can directly instantiate it's JMS Objects like
+ * Queue, ConnectionFactory, etc. without having to use JNDI at all.
+ *
+ * For more information please see the readme.html file.
+ *
+ * @author Tim Fox
+ *
+ */
+public class InstantiateConnectionFactoryExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new InstantiateConnectionFactoryExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ try
+ {
+ // Step 1. Directly instantiate the JMS Queue object.
+ Queue queue = HornetQJMSClient.createQueue("exampleQueue");
+
+ // Step 2. Instantiate the TransportConfiguration object which contains the knowledge of what transport to use,
+ // The server port etc.
+
+ Map connectionParams = new HashMap();
+ connectionParams.put(TransportConstants.PORT_PROP_NAME, 5446);
+
+ TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(),
+ connectionParams);
+
+ // Step 3 Directly instantiate the JMS ConnectionFactory object using that TransportConfiguration
+ ConnectionFactory cf = HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9. Create a JMS Message Consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 10. Start the Connection
+ connection.start();
+
+ // Step 11. Receive the message
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+
+ System.out.println("Received message: " + messageReceived.getText());
+
+ return true;
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..8bcd6b7e3f
--- /dev/null
+++ b/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,45 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..1802d08442
--- /dev/null
+++ b/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/instantiate-connection-factory/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/interceptor/pom.xml b/examples/jms/interceptor/pom.xml
new file mode 100644
index 0000000000..e8a2546ab4
--- /dev/null
+++ b/examples/jms/interceptor/pom.xml
@@ -0,0 +1,121 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-interceptor-example
+ jar
+ HornetQ JMS Interceptor Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.InterceptorExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-interceptor-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/interceptor/readme.html b/examples/jms/interceptor/readme.html
new file mode 100644
index 0000000000..f85e2872c1
--- /dev/null
+++ b/examples/jms/interceptor/readme.html
@@ -0,0 +1,157 @@
+
+
+ HornetQ JMS Interceptor Example
+
+
+
+
+
+
JMS Interceptor Example
+
+
This example shows you how to implement and configure a simple incoming, server-side interceptor with HornetQ.
+
+
HornetQ allows an application to use an interceptor to hook into the messaging system. All that needs to do is to implement the
+ Interceptor interface, as defined below:
With interceptor, you can handle various events in message processing. In this example, a simple interceptor, SimpleInterceptor, is implemented and configured.
+ When the example is running, the interceptor will print out each events that are passed in the interceptor. And it will add a string property to the message being
+ delivered. You can see that after the message is received, there will be a new string property appears in the received message.
+
+
With our interceptor we always return true from the intercept method. If we were
+ to return false that signifies that no more interceptors are to run or the target
+ is not to be called. Return false to abort processing of the packet.
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/interceptor/src/main/java/org/hornetq/jms/example/InterceptorExample.java b/examples/jms/interceptor/src/main/java/org/hornetq/jms/example/InterceptorExample.java
new file mode 100644
index 0000000000..1af8ab4aec
--- /dev/null
+++ b/examples/jms/interceptor/src/main/java/org/hornetq/jms/example/InterceptorExample.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple JMS example that shows how to implement and use interceptors with HornetQ.
+ *
+ * @author Howard Gao
+ */
+public class InterceptorExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new InterceptorExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perform a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sending message [" + message.getText() +
+ "] with String property: " +
+ message.getStringProperty("newproperty"));
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9. Create a JMS Message Consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 10. Start the Connection
+ connection.start();
+
+ // Step 11. Receive the message
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+
+ System.out.println("Received message [" + messageReceived.getText() +
+ "] with String property: " +
+ messageReceived.getStringProperty("newproperty"));
+
+ return true;
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/interceptor/src/main/java/org/hornetq/jms/example/SimpleInterceptor.java b/examples/jms/interceptor/src/main/java/org/hornetq/jms/example/SimpleInterceptor.java
new file mode 100644
index 0000000000..d8270d179f
--- /dev/null
+++ b/examples/jms/interceptor/src/main/java/org/hornetq/jms/example/SimpleInterceptor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import org.hornetq.api.core.HornetQException;
+import org.hornetq.api.core.Interceptor;
+import org.hornetq.api.core.Message;
+import org.hornetq.api.core.SimpleString;
+import org.hornetq.core.protocol.core.Packet;
+import org.hornetq.core.protocol.core.impl.wireformat.SessionSendMessage;
+import org.hornetq.spi.core.protocol.RemotingConnection;
+
+/**
+ * A simple Interceptor implementation
+ *
+ * @author Howard Gao
+ */
+public class SimpleInterceptor implements Interceptor
+{
+
+ public boolean intercept(final Packet packet, final RemotingConnection connection) throws HornetQException
+ {
+ System.out.println("SimpleInterceptor gets called!");
+ System.out.println("Packet: " + packet.getClass().getName());
+ System.out.println("RemotingConnection: " + connection.getRemoteAddress());
+
+ if (packet instanceof SessionSendMessage)
+ {
+ SessionSendMessage realPacket = (SessionSendMessage)packet;
+ Message msg = realPacket.getMessage();
+ msg.putStringProperty(new SimpleString("newproperty"), new SimpleString("Hello from interceptor!"));
+ }
+ // We return true which means "call next interceptor" (if there is one) or target.
+ // If we returned false, it means "abort call" - no more interceptors would be called and neither would
+ // the target
+ return true;
+ }
+
+}
diff --git a/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..0223c78d0a
--- /dev/null
+++ b/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,47 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+ org.hornetq.jms.example.SimpleInterceptor
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..71b83dd96f
--- /dev/null
+++ b/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/interceptor/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/jaas/pom.xml b/examples/jms/jaas/pom.xml
new file mode 100644
index 0000000000..a8093974b1
--- /dev/null
+++ b/examples/jms/jaas/pom.xml
@@ -0,0 +1,139 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-jaas-example
+ jar
+ HornetQ JMS "JAAS" Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+ 1.1.0
+
+
+ start
+
+ start
+
+
+
+ org.hornetq.jms.example.ExampleLoginModule
+
+
+ org.hornetq.jms.example.ExampleLoginModule
+
+ jboss
+ redhat
+ guest
+
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.JAASExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-jaas-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/jaas/readme.html b/examples/jms/jaas/readme.html
new file mode 100644
index 0000000000..0fef5c55fa
--- /dev/null
+++ b/examples/jms/jaas/readme.html
@@ -0,0 +1,98 @@
+
+
+ HornetQ JAAS Example
+
+
+
+
+
+
JAAS Example
+
+
This example shows you how to configure HornetQ to use JAAS for security.
+
HornetQ can leverage JAAS to delegate user authentication and authorization to existing security infrastructure.
+
+
+ The example will show how to configure HornetQ with JAAS in hornetq-beans.xml
+ (You would use hornetq-jboss-beans.xml if you are running inside JBoss Application
+ Server).
+ It will use a simple LoginModule without any user interaction.
+ The example will create a connection and authenticate the user with this JAAS LoginModule, send a message
+ to a queue and receive it (see the Queue example for a complete description
+ of the application code)
+
+
Note than the example actually sets the security manager via the maven pom.xml, however for we will discuss as if
+ the hornetq-beans.xml is being configured, the example beans file can be found under the src/main/resources
+ directory
+
Example setup
+
HornetQ can use a JAAS security manager by specifying it in hornetq-beans.xml:
+
+ <!-- The security manager using JAAS -->
+ <bean name="HornetQSecurityManager" class="org.hornetq.integration.jboss.security.JAASSecurityManager">
+ <property name="configurationName">org.hornetq.jms.example.ExampleLoginModule</property>
+ <property name="configuration">
+ <inject bean="ExampleConfiguration"/>
+ </property>
+ <property name="callbackHandler">
+ <inject bean="ExampleCallbackHandler" />
+ </property>
+ </bean>
+
+ <!-- JAAS uses a simple LoginModule where the user credentials and roles are
+ specified as options in the constructor -->
+ <bean name="ExampleConfiguration" class="org.hornetq.jms.example.ExampleConfiguration">
+ <constructor>
+ <parameter>org.hornetq.jms.example.ExampleLoginModule</parameter>
+ <parameter>
+ <map class="java.util.HashMap" keyClass="java.lang.String"
+ valueClass="java.lang.String">
+ <entry>
+ <key>user</key>
+ <value>jboss</value>
+ </entry>
+ <entry>
+ <key>pass</key>
+ <value>redhat</value>
+ </entry>
+ <entry>
+ <key>role</key>
+ <value>guest</value>
+ </entry>
+ </map>
+ </parameter>
+ </constructor>
+ </bean>
+
+ <!-- the CallbackHandler does nothing as we don't have any user interaction -->
+ <bean name="ExampleCallbackHandler" class="org.hornetq.jms.example.ExampleCallbackHandler"
+ />
+
+
+
+
the HornetQSecurityManager's configurationName must be the name of the Java class implementing LoginModule
+
the callbackHandler property must be an implementation of CallbackHandler. In this example, the ExampleCallbackHandler
+ does nothing since the authentication requires no user interaction
+
the configuration property must be an implementation of Configuration. For simplicity, we pass directly the
+ user credentials as options to the ExampleConfiguration constructor. These options will be passed to an instance
+ of ExampleLoginModule which will check that the only valid user is "jboss" with the password "redhat"
+ and it has the role "guest".
+
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
The only relevant step with regard to JAAS configuration is step 4 (all the other
+ steps are identical to the Queue example).
+
+
We create a JMS Connection with user "jboss" and password "redhat". Any other
+ combination of name and password won't be valid for the ExampleLoginModule
+
+
\ No newline at end of file
diff --git a/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleCallbackHandler.java b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleCallbackHandler.java
new file mode 100644
index 0000000000..9565d717c2
--- /dev/null
+++ b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleCallbackHandler.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * A ExampleCallbackHandler
+ *
+ * @author Jeff Mesnil
+ */
+public class ExampleCallbackHandler implements CallbackHandler
+{
+
+ public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ // do nothing, authentication is done
+ // by passing credentials directly to the ExampleLoginModule
+ }
+}
diff --git a/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleConfiguration.java b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleConfiguration.java
new file mode 100644
index 0000000000..0400564d4e
--- /dev/null
+++ b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleConfiguration.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.util.Map;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+/**
+ * A ExampleConfiguration
+ *
+ * @author Jeff Mesnil
+ */
+public class ExampleConfiguration extends Configuration
+{
+ private Map options;
+
+ private String loginModuleName;
+
+ public ExampleConfiguration()
+ {
+ }
+
+ public ExampleConfiguration(final String loginModuleName, final Map options)
+ {
+ this.loginModuleName = loginModuleName;
+ this.options = options;
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(final String name)
+ {
+ AppConfigurationEntry entry = new AppConfigurationEntry(loginModuleName,
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options);
+ return new AppConfigurationEntry[] { entry };
+ }
+
+ @Override
+ public void refresh()
+ {
+ }
+}
diff --git a/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleLoginModule.java b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleLoginModule.java
new file mode 100644
index 0000000000..a42a0cf7bc
--- /dev/null
+++ b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/ExampleLoginModule.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.hornetq.spi.core.security.JAASSecurityManager;
+
+/**
+ * A ExampleLoginModule
+ *
+ * @author Jeff Mesnil
+ */
+public class ExampleLoginModule implements LoginModule
+{
+
+ private Map options;
+
+ private Subject subject;
+
+ public ExampleLoginModule()
+ {
+ }
+
+ public boolean abort() throws LoginException
+ {
+ return true;
+ }
+
+ public boolean commit() throws LoginException
+ {
+ return true;
+ }
+
+ public void initialize(final Subject subject,
+ final CallbackHandler callbackHandler,
+ final Map sharedState,
+ final Map options)
+ {
+ this.subject = subject;
+ // the credentials are passed directly to the
+ // login module through the options user, pass, role
+ this.options = options;
+ }
+
+ public boolean login() throws LoginException
+ {
+ Iterator iterator = subject.getPrivateCredentials(char[].class).iterator();
+ char[] passwordChars = iterator.next();
+ String password = new String(passwordChars);
+ Iterator iterator2 = subject.getPrincipals().iterator();
+ System.out.println("subject = " + subject);
+ String user = iterator2.next().getName();
+
+ boolean authenticated = user.equals(options.get("user")) && password.equals(options.get("pass"));
+
+ if (authenticated)
+ {
+ Group roles = new SimpleGroup("Roles");
+ roles.addMember(new JAASSecurityManager.SimplePrincipal((String)options.get("role")));
+ subject.getPrincipals().add(roles);
+ }
+ System.out.format("JAAS authentication >>> user=%s, password=%s\n", user, password);
+ System.out.println("authenticated = " + authenticated);
+ return authenticated;
+
+ }
+
+ public Subject getSubject()
+ {
+ return subject;
+ }
+
+ public boolean logout() throws LoginException
+ {
+ return true;
+ }
+
+ public class SimpleGroup implements Group
+ {
+ private final String name;
+
+ private final Set members = new HashSet();
+
+ public SimpleGroup(final String name)
+ {
+ this.name = name;
+ }
+
+ public boolean addMember(final Principal principal)
+ {
+ return members.add(principal);
+ }
+
+ public boolean isMember(final Principal principal)
+ {
+ return members.contains(principal);
+ }
+
+ public Enumeration extends Principal> members()
+ {
+ return Collections.enumeration(members);
+ }
+
+ public boolean removeMember(final Principal principal)
+ {
+ return members.remove(principal);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+ }
+
+}
diff --git a/examples/jms/jaas/src/main/java/org/hornetq/jms/example/JAASExample.java b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/JAASExample.java
new file mode 100644
index 0000000000..56d2e126df
--- /dev/null
+++ b/examples/jms/jaas/src/main/java/org/hornetq/jms/example/JAASExample.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple JMS Queue example that creates a producer and consumer on a queue and sends then receives a message.
+ * The HornetQ server is configured to use JAAS.
+ *
+ * @author Jeff Mesnil
+ */
+public class JAASExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new JAASExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection with user "jboss" and password "redhat"
+ connection = cf.createConnection("jboss", "redhat");
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ TextMessage message = session.createTextMessage("This is a text message");
+
+ System.out.println("Sent message: " + message.getText());
+
+ // Step 8. Send the Message
+ producer.send(message);
+
+ // Step 9. Create a JMS Message Consumer
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+
+ // Step 10. Start the Connection
+ connection.start();
+
+ // Step 11. Receive the message
+ TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
+
+ System.out.println("Received message: " + messageReceived.getText());
+
+ return true;
+ }
+ finally
+ {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }
+ }
+
+}
diff --git a/examples/jms/jaas/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/jaas/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..b71c85fcaa
--- /dev/null
+++ b/examples/jms/jaas/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,43 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/jaas/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/jaas/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..71b83dd96f
--- /dev/null
+++ b/examples/jms/jaas/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/jms-auto-closeable/pom.xml b/examples/jms/jms-auto-closeable/pom.xml
new file mode 100644
index 0000000000..2d24528eb3
--- /dev/null
+++ b/examples/jms/jms-auto-closeable/pom.xml
@@ -0,0 +1,116 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-auto-closeable-example
+ jar
+ HornetQ JMS Auto Closable Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start
+
+ start
+
+
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.JMSAutoCloseableExample
+
+ jnp://localhost:1099
+
+
+
+
+ stop
+
+ stop
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-auto-closeable-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/jms-auto-closeable/readme.html b/examples/jms/jms-auto-closeable/readme.html
new file mode 100644
index 0000000000..cc92549e4a
--- /dev/null
+++ b/examples/jms/jms-auto-closeable/readme.html
@@ -0,0 +1,76 @@
+
+
+ HornetQ JMS Auto Closable Example
+
+
+
+
+
+
JMS Auto Closable Example
+
+
This example shows you how JMS resources, such as connections, sessions and consumers, in JMS 2 can be automatically closed on error.
+
In this instance we auto close a connection after a subsequent call to a JMS producer send fails
+
+
Example step-by-step
+
To run the example, simply type mvn verify from this directory
+
+
+
First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
We then try to send a message. It is this call that throws an exception as the producer doesn't have the privileges
+ to send a message
+
+ jmsProducer.send(queue, "this message will fail security!");
+
+
+
We catch the exception from the send message and can do what we want, however the JMSContext will have been closed
+ prior to entering the catch block.
+
+ System.out.println("expected exception from jmsProducer.send: " + e.getMessage());
+
+
+
And finally, we close the Initial Context, note we no longer have to worry about clearing up the JMSContext.
+
+
+
+
+
+
diff --git a/examples/jms/jms-auto-closeable/src/main/java/org/hornetq/jms/example/JMSAutoCloseableExample.java b/examples/jms/jms-auto-closeable/src/main/java/org/hornetq/jms/example/JMSAutoCloseableExample.java
new file mode 100644
index 0000000000..99374c8608
--- /dev/null
+++ b/examples/jms/jms-auto-closeable/src/main/java/org/hornetq/jms/example/JMSAutoCloseableExample.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import javax.jms.*;
+import javax.naming.InitialContext;
+
+import org.hornetq.common.example.HornetQExample;
+
+/**
+ * A simple JMS example that shows how AutoCloseable is used by JMS 2 resources.
+ *
+ * @author Andy Taylor
+ */
+public class JMSAutoCloseableExample extends HornetQExample
+{
+ public static void main(final String[] args)
+ {
+ new JMSAutoCloseableExample().run(args);
+ }
+
+ @Override
+ public boolean runExample() throws Exception
+ {
+ InitialContext initialContext = null;
+ try
+ {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = getContext(0);
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Context using the try-with-resources statement
+ try
+ (
+ JMSContext jmsContext = cf.createContext()
+ )
+ {
+ // Step 5. create a jms producer
+ JMSProducer jmsProducer = jmsContext.createProducer();
+
+ // Step 6. Try sending a message, we don't have the appropriate privileges to do this so this will throw an exception
+ jmsProducer.send(queue, "this message will fail security!");
+ }
+ catch(JMSRuntimeException e)
+ {
+ //Step 7. we can handle the new JMSRuntimeException if we want or let the exception get handled elsewhere, the
+ //JMSCcontext will have been closed by the time we get to this point
+ System.out.println("expected exception from jmsProducer.send: " + e.getMessage());
+ }
+
+ return true;
+ }
+ finally
+ {
+ // Step 8. Be sure to close our Initial Context, note that we don't have to close the JMSContext as it is auto closeable
+ //and closed by the vm
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ }
+ }
+}
diff --git a/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-configuration.xml
new file mode 100644
index 0000000000..8ce100590e
--- /dev/null
+++ b/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-configuration.xml
@@ -0,0 +1,42 @@
+
+
+ ${build.directory}/server0/data/messaging/bindings
+
+ ${build.directory}/server0/data/messaging/journal
+
+ ${build.directory}/server0/data/messaging/largemessages
+
+ ${build.directory}/server0/data/messaging/paging
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
+
+
+
+
+
+
+ org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-jms.xml
new file mode 100644
index 0000000000..71b83dd96f
--- /dev/null
+++ b/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-jms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-users.xml
new file mode 100644
index 0000000000..934306c4b5
--- /dev/null
+++ b/examples/jms/jms-auto-closeable/src/main/resources/hornetq/server0/hornetq-users.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/jms-bridge/jms-bridge.png b/examples/jms/jms-bridge/jms-bridge.png
new file mode 100644
index 0000000000..d671bf34b0
Binary files /dev/null and b/examples/jms/jms-bridge/jms-bridge.png differ
diff --git a/examples/jms/jms-bridge/pom.xml b/examples/jms/jms-bridge/pom.xml
new file mode 100644
index 0000000000..50f695b9d7
--- /dev/null
+++ b/examples/jms/jms-bridge/pom.xml
@@ -0,0 +1,165 @@
+
+ 4.0.0
+
+
+ org.hornetq.examples.jms
+ jms-examples
+ 2.5.0-SNAPSHOT
+
+
+ hornetq-jms-jms-bridge-example
+ jar
+ HornetQ JMS Bridge Example
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-examples-common
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jboss-as-integration
+ ${project.version}
+
+
+ org.jboss
+ jboss-transaction-spi
+
+
+ org.jboss.jbossts.jts
+ jbossjts-jacorb
+
+
+ org.jboss.spec.javax.jms
+ jboss-jms-api_2.0_spec
+
+
+
+
+
+
+ org.hornetq
+ hornetq-maven-plugin
+
+
+ start0
+
+ start
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ start1
+
+ start
+
+
+ 1199
+ 1198
+ ${basedir}/target/classes/hornetq/server1
+ true
+
+
+
+ runClient
+
+ runClient
+
+
+ org.hornetq.jms.example.JMSBridgeExample
+
+ jnp://localhost:1099
+ jnp://localhost:1199
+
+
+
+ exampleConfigDir
+ ${basedir}/target/classes/hornetq
+
+
+
+
+
+ stop0
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server0
+
+
+
+ stop1
+
+ stop
+
+
+ ${basedir}/target/classes/hornetq/server1
+
+
+
+
+
+ org.hornetq.examples.jms
+ hornetq-jms-jms-bridge-example
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-core-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-server
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${project.version}
+
+
+ org.hornetq
+ hornetq-jms-server
+ ${project.version}
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+ org.jboss.javaee
+ jboss-jms-api
+ 1.1.0.GA
+
+
+ org.jboss.naming
+ jnpserver
+ 5.0.3.GA
+
+
+
+ false
+
+
+ build.directory
+ ${basedir}/target/
+
+
+
+
+
+
+
+
diff --git a/examples/jms/jms-bridge/readme.html b/examples/jms/jms-bridge/readme.html
new file mode 100644
index 0000000000..2d6b8b196b
--- /dev/null
+++ b/examples/jms/jms-bridge/readme.html
@@ -0,0 +1,220 @@
+
+
+ HornetQ JMS Bridge Example
+
+
+
+
+
+
JMS Bridge Example
+
This example shows you how to create a JMS Bridge between two HornetQ servers.
+
+
The example will use two HornetQ servers:
+
+
Server #0 – the Source server. It will be configured with a JMS Topic bound to JNDI under /source/topic
+
Server #1 – the Target server. It will be configured with a JMS Queue bound to JNDI under /target/queue
+
+
Both HornetQ server will run their own JNDI server used by the JMS Bridge and the JMS Client to lookup JMS
+ resources (ConnectionFactory and Destination).
+
The JMS Bridge will be started in the example code and be configured to bridge messages from the source destination
+ (the topic hosted on server #0) and the target destination (the queue hosted on server #1)
+
The client will check the bridge works by:
+
+
sending a message to the source topic
+
receive a message from the target queue
+
check that both messages correspond to the same content.
+
+
JMS Bridge Configuration
+
The JMS Bridge is a POJO that we configure with both source and target
+ JNDI configurations. In the actual example we are programatically creating the Bridge, however the following section
+ describes how you would do this if you wanted to deploy with an actual HornetQ server via the hornetq-beans.xml.
+
+
Configuring the Bridge with the JBoss Microcontainer
+
+ in which we inject JNDI configurations
+ so that it looks up its source and target JMS resources.
+ The JMS Bridge is defined a bean and setup by JBoss Microntainer in the same VM than Server #1, the target server.
+
+ The JMS Bridge sample configuration can be found in resources/hornetq-beans.xml, firstly we define the
+ Bridge itself:
+
the JMSBridgeImpl constructor is used to inject all the properties required to run the JMS Bridge.
+
Its first four arguments defines how the bridge will lookup:
+
+
its source JMS ConnectionFactory
+
its source JMS Destination
+
its target JMS ConnectionFactory
+
its target JMS Destination
+
+
Using other POJOs, the JMS Bridge is configured to retrieve:
+
+
its source JMS ConnectionFactory by looking up /source/ConnectionFactory using
+ the SourceJNDI configuration
+
its source JMS Destination by looking up /source/topic using
+ the SourceJNDI configuration
+
its target JMS ConnectionFactory by looking up /target/ConnectionFactory using
+ the TargetJNDI configuration
+
its target JMS ConnectionFactory by looking up /target/queue using
+ the TargetJNDI configuration
+
+
In turn, SourceJNDI and TargetJNDI are POJOs defining how to connect to JNDI server.
+ SourceJNDI URL must point to your source server, while LocalJNDI must point to your target server:
+ TextMessage message = sourceSession.createTextMessage("this is a text message sent at " + System.currentTimeMillis());
+ sourceProducer.send(message);
+
+
+
We close the connection to the source server
+
+ sourceConnection.close();
+
+
+
At this point, the JMS Bridge will consume the message from the source topic and
+ sends it to the target queue.
+ The client will check the bridge works by consuming a message from the target queue.
+
+
We look up the JMS resources from the target server
We display the message ID and its "bridged" message ID
+
+ System.out.format("Message ID : %s\n", messageReceived.getJMSMessageID());
+ System.out.format("Bridged Message ID : %s\n", messageReceived.getStringProperty("HQ_BRIDGE_MSG_ID_LIST"));
+
+
+
Note that the message received from the target queue is not the same message sent to the source topic
+ (their message IDs are different) but they have the same content.
+
+
And finally, we stop the Bridge and always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
The Java EE JMS Bridge example shows how to configure a JMS Bridge
+ inside JBoss Application Server to bridge destinations from the same server.
+
+
+
+
\ No newline at end of file
diff --git a/examples/jms/jms-bridge/src/main/java/org/hornetq/jms/example/JMSBridgeExample.java b/examples/jms/jms-bridge/src/main/java/org/hornetq/jms/example/JMSBridgeExample.java
new file mode 100644
index 0000000000..c16f72dcde
--- /dev/null
+++ b/examples/jms/jms-bridge/src/main/java/org/hornetq/jms/example/JMSBridgeExample.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2005-2014 Red Hat, Inc.
+ * Red Hat 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.
+ */
+package org.hornetq.jms.example;
+
+import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
+import org.hornetq.jms.bridge.JMSBridge;
+import org.hornetq.jms.bridge.QualityOfServiceMode;
+import org.hornetq.jms.bridge.impl.JMSBridgeImpl;
+import org.hornetq.jms.bridge.impl.JNDIConnectionFactoryFactory;
+import org.hornetq.jms.bridge.impl.JNDIDestinationFactory;
+
+import java.util.Hashtable;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.naming.InitialContext;
+
+/**
+ * An example which sends a message to a source topic and consume from a target queue.
+ * The source and target destinations are located on 2 different HornetQ server.
+ * The source and target queues are bridged by a JMS Bridge configured and running on the "target" server.
+ *
+ * @author Jeff Mesnil
+ */
+public class JMSBridgeExample
+{
+ public static void main(final String[] args) throws Exception
+ {
+ if (args.length != 2)
+ {
+ throw new IllegalArgumentException("JMSBridgeExample needs 2 arguments: