-
Notifications
You must be signed in to change notification settings - Fork 888
/
master.xml
1959 lines (1601 loc) · 76.1 KB
/
master.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.docbook.org/xml/4.4/docbookx.dtd">
<book>
<bookinfo>
<title>HornetQ REST Interface</title>
<releaseinfo>1.0-beta-3</releaseinfo>
</bookinfo>
<toc></toc>
<preface id="preface" revision="1">
<title>Preface</title>
<para>Commercial development support, production support and training for
RESTEasy and HornetQ is available through JBoss, a division of Red Hat
Inc. (see http://www.jboss.com/).</para>
<para></para>
</preface>
<chapter>
<title>Introduction</title>
<para>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:</para>
<para><programlisting>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>
</programlisting>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.</para>
<para></para>
<sect1>
<title>Goals of REST Interface</title>
<para>Why would you want to use HornetQ's REST interface? What are the
goals of the REST interface?</para>
<itemizedlist>
<listitem>
<para>Easily usable by machine-based (code) clients.</para>
</listitem>
<listitem>
<para>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.</para>
</listitem>
<listitem>
<para>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 <ulink
url="http://rest-star.org">REST-*</ulink> effort.)</para>
</listitem>
<listitem>
<para>No envelope (i.e. SOAP) or feed (i.e. 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.</para>
</listitem>
<listitem>
<para>Leverage the reliability, scalability, and clustering features
of HornetQ on the back end without sacrificing the simplicity of a
REST interface.</para>
<para></para>
</listitem>
</itemizedlist>
</sect1>
</chapter>
<chapter>
<title>Installation and Configuration</title>
<para>HornetQ's REST interface is installed as a Web archive (WAR). It
depends on the <ulink url="http://jboss.org/resteasy">RESTEasy</ulink>
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 (i.e.
you're deploying within JBoss 6 AppServer) or you want the HornetQ REST
WAR to startup and manage the HornetQ server.</para>
<sect1>
<title>Installing Within Pre-configured Environment</title>
<para>The section should be used when you want to use the HornetQ REST
interface in an environment that already has HornetQ installed and
running, i.e. JBoss 6 Application Server. You must create a Web archive
(.WAR) file with the following web.xml settings:</para>
<programlisting><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</programlisting>
<para>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.</para>
<programlisting><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>
<repositories>
<repository>
<id>jboss</id>
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
</repository>
</repositories>
<build>
<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>1.0-beta-3</version>
</dependency>
</dependencies>
</project>
</programlisting>
<para></para>
</sect1>
<sect1>
<title>Bootstrapping HornetQ Along with REST</title>
<para>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:</para>
<programlisting><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></programlisting>
<para>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!</para>
<programlisting><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>
<repositories>
<repository>
<id>jboss</id>
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
</repository>
</repositories>
<build>
<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.1.1.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms</artifactId>
<version>2.1.1.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.jms</groupId>
<artifactId>jboss-jms-api_1.1_spec</artifactId>
<version>1.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.hornetq.rest</groupId>
<artifactId>hornetq-rest</artifactId>
<version>1.0-beta-3</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>2.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>2.0.0.GA</version>
</dependency>
</dependencies>
</project></programlisting>
<para></para>
</sect1>
<sect1>
<title>REST Configuration</title>
<para>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
<literal>rest.messaging.config.file</literal> to specify the name of the
configuration file. Below is the format of the XML configuration file
and the default values for each.</para>
<programlisting><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-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
</programlisting>
<para>Let's give an explanation of each config option.</para>
<variablelist>
<varlistentry>
<term>server-in-vm-id</term>
<listitem>
<para>The HornetQ REST impl uses the IN-VM transport to
communicate with HornetQ. It uses the default server id, which is
"0".</para>
</listitem>
</varlistentry>
<varlistentry>
<term>use-link-headers</term>
<listitem>
<para>By default, all links (URLs) are published using custom
headers. You can instead have the HornetQ REST implementation
publish links using the <ulink
url="http://tools.ietf.org/html/draft-nottingham-http-link-header-10">Link
Header specification</ulink> instead if you desire.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>default-durable-send</term>
<listitem>
<para>Whether a posted message should be persisted by default if
the user does not specify a durable query parameter.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>dups-ok</term>
<listitem>
<para>If this is true, no duplicate detection protocol will be
enforced for message posting.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>topic-push-store-dir</term>
<listitem>
<para>This must be a relative or absolute file system path. This
is a directory where push registrations for topics are stored. See
Chapter 6.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>queue-push-store-dir</term>
<listitem>
<para>This must be a relative or absolute file system path. This
is a directory where push registrations for queues are stored. See
Chapter 6.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>producer-session-pool-size</term>
<listitem>
<para>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.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>session-timeout-task-interval</term>
<listitem>
<para>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.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>consumer-session-timeout-seconds</term>
<listitem>
<para>Timeout in seconds for pull consumers/subscriptions that
remain idle for that amount of time.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>consumer-window-size</term>
<listitem>
<para>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.</para>
</listitem>
</varlistentry>
</variablelist>
</sect1>
</chapter>
<chapter>
<title>HornetQ REST Interface Basics</title>
<para>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.</para>
<sect1>
<title>Queue and Topic Resources</title>
<para>To interact with a queue or topic you do a HEAD or GET request on
the following relative URI pattern:</para>
<programlisting>/queues/{name}
/topics/{name}
</programlisting>
<para>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
<literal>{name}</literal> 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
<literal>hornetq-jms.xml</literal> file, the URI name should be
"jms.topic.foo". If you have configured a JMS queue name "bar" within
your <literal>hornetq-jms.xml</literal> 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.</para>
<programlisting>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
</programlisting>
<para>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.</para>
<para></para>
</sect1>
<sect1>
<title>Queue Resource Response Headers</title>
<para>Below is a list of response headers you should expect when
interacting with a Queue resource.</para>
<variablelist>
<varlistentry>
<term>msg-create</term>
<listitem>
<para>This is a URL you POST messages to. The semantics of this
link are described in Chapter 4.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-create-with-id</term>
<listitem>
<para>This is a URL template you POST message to. The semantics of
this link are described in Chapter 4.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-pull-consumers</term>
<listitem>
<para>This is a URL for creating consumers that will pull from a
queue. The semantics of this link are described in Chapter
5.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-push-consumers</term>
<listitem>
<para>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 Chapter 6</para>
</listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1>
<title>Topic Resource Respones Headers</title>
<para>Below is a list of response headers you should expect when
interacting with a Topic resource.</para>
<variablelist>
<varlistentry>
<term>msg-create</term>
<listitem>
<para>This is a URL you POST messages to. The semantics of this
link are described in Chapter 4.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-create-with-id</term>
<listitem>
<para>This is a URL template you POST messages to. The semantics
of this link are described in Chapter 4.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-pull-subscriptions</term>
<listitem>
<para>This is a URL for creating subscribers that will pull from a
topic. The semantics of this link are described in Chapter
5.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-push-subscriptions</term>
<listitem>
<para>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 Chapter 6.</para>
</listitem>
</varlistentry>
</variablelist>
<para></para>
</sect1>
</chapter>
<chapter>
<title>Posting Messages</title>
<para>This chapter discusses the protocol for posting messages to a queue
or a topic. In Chapter 3, you saw that a queue or topic resource publishes
variable custom headers that are links to other RESTful resources. The
<literal>msg-create</literal> header is the URL you post messages 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:</para>
<orderedlist>
<listitem>
<para>Obtain the starting <literal>msg-create</literal> header from
the queue or topic resource.</para>
<para><programlisting>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}
</programlisting></para>
</listitem>
<listitem>
<para>Do a POST to the URL contained in the
<literal>msg-create</literal> header.</para>
<para><programlisting>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/002
</programlisting>A successful response will return a 201 response code. Also
notice that a <literal>msg-create-next</literal> response header is
sent as well. You must use this URL to POST your next message.</para>
</listitem>
<listitem>
<para>POST your next message to the queue using the URL returned in
the <literal>msg-create-next</literal> header.</para>
<para><programlisting>POST /queues/jms.queue.bar/create/002
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/003
</programlisting>Continue using the new <literal>msg-create-next</literal>
header returned with each response.</para>
</listitem>
</orderedlist>
<para>It is <emphasis>VERY IMPORTENT</emphasis> that you never re-use
returned <literal>msg-create-next</literal> headers to post new messages.
This URL may be uniquely generated for each message and used for duplicate
detection. If you lose the URL within the
<literal>msg-create-next</literal> header, then just go back to the queue
or topic resource to get the msg-create URL.</para>
<sect1>
<title>Duplicate Detection</title>
<para>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
<literal>dups-ok</literal> config option to <literal>false</literal> as
described in Chapter 3. 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:</para>
<orderedlist>
<listitem>
<para>Obtain the starting <literal>msg-create</literal> header from
the queue or topic resource.</para>
<para><programlisting>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}
</programlisting></para>
</listitem>
<listitem>
<para>Do a POST to the URL contained in the
<literal>msg-create</literal> header.</para>
<para><programlisting>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/001
</programlisting>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 <literal>Location</literal>
header.</para>
</listitem>
<listitem>
<para>re-POST your message to the URL provided within the
<literal>Location</literal> header<literal>.</literal></para>
<para><programlisting>POST /queues/jms.queue.bar/create/001
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/002
</programlisting>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 <literal>msg-create-next</literal> header
returned with each response.</para>
</listitem>
<listitem>
<para>POST any new message to the returned
<literal>msg-create-next</literal> header.</para>
<para><programlisting>POST /queues/jms.queue.bar/create/002
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/003</programlisting>If
there ever is a network problem, just repost to the URL provided in
the <literal>msg-create-next</literal> header.</para>
</listitem>
</orderedlist>
<para>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
<literal>DUPLICATE_DETECTION_ID</literal> property of the JMS message
that is actually posted to the system.</para>
<para>An alternative to this approach is to use the
<literal>msg-create-with-id</literal> header. This is not an invokable
URL, but a URL template. The idea is that the client provides the
<literal>DUPLICATE_DETECTION_ID</literal> and creates it's own
<literal>create-next</literal> URL. The
<literal>msg-create-with-id</literal> header looks like this (you've see
it in previous examples, but we haven't used it):</para>
<programlisting>msg-create-with-id: http://example.com/queues/jms.queue.bar/create/{id}</programlisting>
<para>You see that it is a regular URL appended with a
<literal>{id}</literal>. This <literal>{id}</literal> is a pattern
matching substring. A client would generate its
<literal>DUPLICATE_DETECTION_ID</literal> and replace
<literal>{id}</literal> with that generated id, then POST to the new
URL. The URL the client creates works exactly like a
<literal>create-next</literal> URL described earlier. The response of
this POST would also return a new <literal>msg-create-next</literal>
header. The client can continue to generate its own
DUPLICATE_DETECTION_ID, or use the new URL returned via the
<literal>msg-create-nex</literal>t header.</para>
<para>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
<literal>DUPLICATE_DETECTION_ID</literal> once.</para>
</sect1>
<sect1>
<title>Persistent Messages</title>
<para>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 <literal>durable</literal> to true when you post
your messages to the URLs returned in the <literal>msg-create</literal>,
<literal>msg-create-with-id</literal>, or
<literal>msg-create-next</literal> headers. here's an example of
that.</para>
<programlisting>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>
</programlisting>
</sect1>
<sect1>
<title>Expiration and Priority</title>
<para>You can set he expiration and the priority of the message in the queue or topic by setting an additional query parameter. The <literal>expiration</literal> query parameter is an integer expressing the time in milliseconds until the message should be expired. The <literal>priority</literal> is another query parameter with an integer value between 0 and 9 expressing the priority of the message. i.e.:</para>
<programlisting>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>
</programlisting>
</sect1>
</chapter>
<chapter>
<title>Consuming Messages via Pull</title>
<para>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.</para>
<para>You create consumer resources by doing a simple POST to the URL
published by the <literal>msg-pull-consumers</literal> response header if
you're interacting with a queue, the
<literal>msg-pull-subscribers</literal> response header if you're
interacting with a topic. These headers are provided by the main queue or
topic resource discussed in Chapter 3. Doing an empty POST to one of these
URLs will create a consumer resource that follows an auto-acknowledge
protocol and, if you're interacting with a topic, creates a temporty
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 (<literal>application/x-www-form-urlencoded</literal>)
described below.</para>
<variablelist>
<varlistentry>
<term>autoAck</term>
<listitem>
<para>A value of <literal>true</literal> or <literal>false</literal>
can be given. This defaults to <literal>true</literal> if you do not
pass this parameter.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>durable</term>
<listitem>
<para>A value of <literal>true</literal> or <literal>false</literal>
can be given. This defaults to <literal>false</literal> 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.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>name</term>
<listitem>
<para>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.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>selector</term>
<listitem>
<para>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 '-'
charactor is converted to a '$'.</para>
</listitem>
</varlistentry>
</variablelist>
<sect1>
<title>Auto-Acknowledge</title>
<para>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.</para>
<variablelist>
<varlistentry>
<term>msg-pull-consumers</term>
<listitem>
<para>The URL of a factory resource for creating queue consumer
resources. You will pull from these created resources.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-pull-subscriptions</term>
<listitem>
<para>The URL of a factory resource for creating topic
subscription resources. You will pull from the created
resources.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-consume-next</term>
<listitem>
<para>The URL you will pull the next message from. This is
returned with every response.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>msg-consumer</term>
<listitem>
<para>This is a URL pointing back to the consumer or subscription
resource created for the client.</para>
</listitem>
</varlistentry>
</variablelist>
<sect2>
<title>Creating an Auto-Ack Consumer or Subscription</title>
<para>Here is an example of creating an auto-acknowledged queue pull
consumer.</para>
<orderedlist>
<listitem>
<para>Find the pull-consumers URL by doing a HEAD or GET request
to the base queue resource.</para>
<programlisting>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
</programlisting>
</listitem>
<listitem>
<para>Next do an empty POST to the URL returned in the
<literal>msg-pull-consumers</literal> header.</para>
<programlisting>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
</programlisting>
<para>The <literal>Location</literal> 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.</para>
</listitem>
</orderedlist>
<para>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.</para>
<orderedlist>
<listitem>
<para>Find the <literal>pull-subscriptions</literal> URL by doing
a HEAD or GET request to the base topic resource</para>
<programlisting>HEAD /topics/jms.topic.bar HTTP/1.1
Host: example.com
--- Response ---