File: api.xml

package info (click to toggle)
libjgroups-java 2.12.2.Final-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 8,724 kB
  • sloc: java: 109,098; xml: 9,423; sh: 174; makefile: 4
file content (1624 lines) | stat: -rw-r--r-- 71,144 bytes parent folder | download | duplicates (4)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="user-channel">
  <title>API</title>

  <para>This chapter explains the classes available in JGroups that will be
  used by applications to build reliable group communication applications. The
  focus is on creating and using channels.</para>

  <para>Information in this document may not be up-to-date, but the nature of
  the classes in the JGroups toolkit described here is the same. For the most
  up-to-date information refer to the Javadoc-generated documentation in the
  <filename>doc/javadoc</filename> directory.</para>

  <para>All of the classes discussed below reside in the
  <classname>org.jgroups</classname> package unless otherwise
  mentioned.</para>

  <section>
    <title>Utility classes</title>

    <para>The <classname>org.jgroups.util.Util</classname> class contains a
    collection of useful functionality which cannot be assigned to any
    particular package.</para>

    <section>
      <title>objectToByteBuffer(), objectFromByteBuffer()</title>

      <para>The first method takes an object as argument and serializes it
      into a byte buffer (the object has to be serializable or
      externalizable). The byte array is then returned. This method is often
      used to serialize objects into the byte buffer of a message. The second
      method returns a reconstructed object from a buffer. Both methods throw
      an exception if the object cannot be serialized or unserialized.</para>
    </section>
  </section>

  <section>
    <title>Interfaces</title>

    <para>These interfaces are used with some of the APIs presented below,
    therefore they are listed first.</para>

    <section>
      <title>MessageListener</title>

      <para>Contrary to the pull-style of channels, some building blocks (e.g.
      <classname>PullPushAdapter</classname> ) provide an event-like
      <emphasis>push-style</emphasis> message delivery model. In this case,
      the entity to be notified of message reception needs to provide a
      callback to be invoked whenever a message has been received. The
      <classname>MessageListener</classname> interface below provides a method
      to do so:
          <screen>
          public interface MessageListener {
              public void receive(Message msg);
              byte[] getState();
              void setState(byte[] state);
          }
          </screen>
      </para>

      <para>Method <methodname>receive()</methodname> will be called when a
      message is received. The <methodname>getState()</methodname> and
      <methodname>setState()</methodname> methods are used to fetch and set
      the group state (e.g. when joining). Refer to <xref
      linkend="GetState" /> for a discussion of state transfer.</para>
    </section>

    <section>
      <title>ExtendedMessageListener</title>

      <para>
          JGroups release 2.3 introduced ExtendedMessageListener enabling
          partial state transfer (refer to <xref linkend="PartialStateTransfer" />
          ) while release 2.4 further expands ExtendedMessageListener with
          streaming state transfer callbacks:

      <screen>
         public interface ExtendedMessageListener extends MessageListener {
             byte[] getState(String state_id);
             void setState(String state_id, byte[] state);
                      
             /*** since JGroups 2.4 *****/
             void getState(OutputStream ostream);
             void getState(String state_id, OutputStream ostream);
             void setState(InputStream istream);
             void setState(String state_id, InputStream istream);
          }
       </screen>
      </para>

    </section>

    <section id="MembershipListener">
      <title>MembershipListener</title>

      <para>
          The <classname>MembershipListener</classname> interface is similar to the <classname>MessageListener</classname>
          interface above: every time a new view, a suspicion message, or a block event is received, the corresponding
          method of the class implementing <classname>MembershipListener</classname> will be called.

          <screen>
            public interface MembershipListener {
                public void viewAccepted(View new_view);
                public void suspect(Object suspected_mbr);
                public void block();
            }
          </screen>
      </para>

        <para>Oftentimes the only method containing any functionality will be
            <methodname>viewAccepted()</methodname> which notifies the receiver that
            a new member has joined the group or that an existing member has left or
            crashed. The <methodname>suspect()</methodname> callback is invoked by
            JGroups whenever a member if suspected of having crashed, but not yet
            excluded <footnote>
            <para>It could be that the member is suspected falsely, in which
                case the next view would still contain the suspected member (there
                is currently no <methodname>unsuspect()</methodname> method</para>
        </footnote>.</para>
        <para>
            The <methodname>block()</methodname> method is called
            to notify the member that it will soon be blocked sending messages. This
            is done by the FLUSH protocol, for example to ensure that nobody is sending
            messages while a state transfer is in progress. When block() returns, any thread
            sending messages will be blocked, until FLUSH unblocks the thread again, e.g.
            after the state has been transferred successfully.
         </para>

        <para>
            Therefore, block() can be used to send pending messages or complete some other work.
         </para>

        <para>
            Note that block() should be brief, or else the entire FLUSH protocol is blocked.
        </para>
        <note>
            <title>Sending messages in callbacks</title>
            <para>
                Note that anything that could block should <emphasis>not</emphasis> be done in a callback.
                This includes sending of messages;
                if we have FLUSH on the stack, and send a message in a viewAccepted() callback, then the following
                happens: the FLUSH protocol blocks all (multicast) messages before installing a view, then installs
                the view, then unblocks. However, because installation of the view triggers the viewAccepted() callback,
                sending of messages inside of viewAccepted() will block. This in turn blocks the viewAccepted() thread,
                so the flush will never return !
            </para>
            <para>
                If we need to send a message in a callback, the sending should be done on a separate thread, or a timer
                task should be submitted to the timer.
            </para>
        </note>
    </section>


      <section id="ExtendedMembershipListener">
          <title>ExtendedMembershipListener</title>

          <para>
              The <classname>ExtendedMembershipListener</classname> interface extends
              <classname>MembershipListener</classname>:

          <screen>
              public interface ExtendedMembershipListener extends MembershipListener {
                  public void unblock();
              }
          </screen>
          </para>

          <para>
              The <methodname>unblock()</methodname> method is called
              to notify the member that the FLUSH protocol has completed and the member can resume
              sending messages. If the member did not stop sending messages on block(), FLUSH simply blocked them and
              will resume, so no action is required from a member. Implementation of the unblock() callback is optional.
          </para>

      </section>



    <section>
      <title>ChannelListener</title>
        <para>
        <screen>
           public interface ChannelListener {
               void channelConnected(Channel channel);
               void channelDisconnected(Channel channel);
               void channelClosed(Channel channel);
               void channelShunned(); // deprecated in 2.8
               void channelReconnected(Address addr); // deprecated in 2.8
           }
        </screen>
        </para>

      <para>A class implementing <classname>ChannelListener</classname> can
      use the <methodname>Channel.setChannelListener()</methodname> method to
      register with a channel to obtain information about state changes in a
      channel. Whenever a channel is closed, disconnected or opened a callback
      will be invoked.</para>
    </section>

    <section>
      <title>Receiver</title>
        <para>
      <screen>
         public interface Receiver extends MessageListener, MembershipListener {
         }
      </screen>
        </para>

      <para>A Receiver can be used to receive messages and view
      changes in push-style; rather than having to pull these events from a
      channel, they will be dispatched to the receiver as soon as they have
      been received. This saves one thread (application thread, pulling
      messages from a channel, or the PullPushAdapter thread</para>
        <para>
            Note that <methodname>JChannel.receive()</methodname> has been deprecated and will be removed in 3.0. The
            preferred way of receiving messages is now via a Receiver callback (push style).
        </para>
    </section>

    <section>
      <title>ExtendedReceiver</title>
        <para>
      <screen>
      public interface ExtendedReceiver extends ExtendedMessageListener, MembershipListener {
      }
      </screen>
         </para>

      <para>This is a receiver who will be able to handle partial state transfer</para>
    </section>

      <section>
          <title>ReceiverAdapter and ExtendedReceiverAdapter</title>
          <para>
              These classes implement Receiver and ExtendedReceiver. When implementing a callback, one can simply
              extend ReceiverAdapter and overwrite receive() in order to not having to implement all callbacks of
              the interface.
          </para>
      </section>

    <note>
      <title>Merging of Extended interfaces with their super interfaces</title>

        <para>The Extended- interfaces (ExtendedMessageListener, ExtendedReceiver) will be merged with their parents in
            the 3.0 release of JGroups. The reason is that this will create an API backwards
            incompatibility, which we didn't want to introduce in the 2.x series.</para>
    </note>
  </section>

  <section>
    <title>Address</title>

    <para>Each member of a group has an address, which uniquely identifies the
    member. The interface for such an address is Address, which requires
    concrete implementations to provide methods for comparison and sorting of
    addresses, and for determination whether the address is a multicast
    address. JGroups addresses have to implement the following interface:

    <screen>
       public interface Address extends Externalizable, Comparable, Cloneable {
           boolean isMulticastAddress();
           int size();
       }
    </screen>
    </para>

    <para>
        <emphasis>Please never use implementations of Address directly; Address should always be used
        as an opaque identifier of a cluster node !</emphasis>
    </para>

    <para>Actual implementations of addresses are often generated by the
    bottommost protocol layer (e.g. UDP or TCP). This allows for all possible
    sorts of addresses to be used with JGroups, e.g. ATM.</para>

    <para>In JChannel, it is the IP address of the host on which the stack is
    running and the port on which the stack is receiving incoming messages; it
    is represented by the concrete class
    <classname>org.jgroups.stack.IpAddress</classname>. Instances of this
    class are only used <emphasis>within</emphasis> the JChannel protocol
    stack; <emphasis>users of a channel see addresses (of any kind) only as
    Addresses</emphasis>. Since an address uniquely identifies a channel, and
    therefore a group member, it can be used to send messages to that group
    member, e.g. in Messages (see next section).</para>
      <para>
          In 2.8, the default implementation of Address was changed from <classname>IpAddress</classname> to
          <classname>org.jgroups.util.UUID</classname>.
      </para>
  </section>

  <section>
    <title>Message</title>

    <para>Data is sent between members in the form of messages (
    <classname>org.jgroups.Message</classname> ). A message can be sent by a member to a
    <emphasis>single member</emphasis> , or to <emphasis>all
    members</emphasis> of the group of which the channel is an endpoint. The
    structure of a message is shown in <xref linkend="MessageFig" /> .</para>

    <figure id="MessageFig">
      <title>Structure of a message</title>

      <graphic align="center" fileref="images/Message.png" format="PNG" />
    </figure>

    <para>A message contains 5 fields:</para>

    <variablelist>
      <varlistentry>
        <term>Destination address</term>

        <listitem>
          <para>The address of the receiver. If <literal>null</literal> , the
          message will be sent to all current group members</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Source address</term>

        <listitem>
          <para>The address of the sender. Can be left <literal>null</literal>
          , and will be filled in by the transport protocol (e.g. UDP) before
          the message is put on the network</para>
        </listitem>
      </varlistentry>

        <varlistentry>
            <term>Flags</term>

            <listitem>
                <para>This is one byte used for flags. The currently recognized flags are OOB, LOW_PRIO and HIGH_PRIO.
                    See the discussion on the concurrent stack for OOB.
                </para>
            </listitem>
        </varlistentry>

        <varlistentry>
        <term>Payload</term>

        <listitem>
          <para>The actual data (as a byte buffer). The Message class contains
          convenience methods to set a serializable object and to retrieve it
          again, using serialization to convert the object to/from a byte
          buffer.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Headers</term>

        <listitem>
          <para>A list of headers that can be attached to a message. Anything
          that should not be in the payload can be attached to a message as a
          header. Methods <methodname>putHeader()</methodname> ,
          <methodname>getHeader()</methodname> and
          <methodname>removeHeader()</methodname> of Message can be used to
          manipulate headers.</para>
        </listitem>
      </varlistentry>
    </variablelist>

    <para>A message is similar to an IP packet and consists of the payload (a
    byte buffer) and the addresses of the sender and receiver (as Addresses).
    Any message put on the network can be routed to its destination (receiver
    address), and replies can be returned to the sender's address.</para>

    <para>A message usually does not need to fill in the sender's address when
    sending a message; this is done automatically by the protocol stack before
    a message is put on the network. However, there may be cases, when the
    sender of a message wants to give an address different from its own, so
    that for example, a response should be returned to some other
    member.</para>

    <para>The destination address (receiver) can be an Address, denoting the
    address of a member, determined e.g. from a message received previously,
    or it can be <literal>null</literal> , which means that the message will
    be sent to all members of the group. A typical multicast message, sending
    string <literal>"Hello"</literal> to all members would look like
    this:

      <screen>
         Message msg=new Message(null, null, "Hello");
         channel.send(msg);
      </screen>
      </para>
  </section>


  <section>
    <title>View</title>

    <para>A View ( <classname>View</classname> ) is a list of the current
    members of a group. It consists of a <classname>ViewId</classname> , which
    uniquely identifies the view (see below), and a list of members. Views are
    set in a channel automatically by the underlying protocol stack whenever a
    new member joins or an existing one leaves (or crashes). All members of a
    group see the same sequence of views.</para>

    <para>Note that there is a comparison function which orders all the
    members of a group in the same way. Usually, the first member of the list
    is the <emphasis>coordinator</emphasis> (the one who emits new views).
    Thus, whenever the membership changes, every member can determine the
    coordinator easily and without having to contact other members.</para>

    <para>The code below shows how to send a (unicast) message to the first
    member of a view (error checking code omitted):

    <screen>
       View view=channel.getView();
       Address first=view.getMembers().first();
       Message msg=new Message(first, null, "Hello world");
       channel.send(msg);
    </screen>
    </para>

    <para>Whenever an application is notified that a new view has been
    installed (e.g. by
    <methodname>Receiver.viewAccepted()</methodname>, the view is already set in
    the channel. For example, calling
    <methodname>Channel.getView()</methodname> in a
    <methodname>viewAccepted()</methodname> callback would return the same
    view (or possibly the next one in case there has already been a new view
    !).</para>

    <section>
      <title>ViewId</title>

      <para>The ViewId is used to uniquely number views. It consists of the
      address of the view creator and a sequence number. ViewIds can be
      compared for equality and put in a hashtable as they implement equals()
      and hashCode() methods.<footnote>Note that the latter 2 methods only take the ID into account.</footnote></para>
    </section>

    <section id="MergeView">
      <title>MergeView</title>

      <para>Whenever a group splits into subgroups, e.g. due to a network
      partition, and later the subgroups merge back together, a MergeView
      instead of a View will be received by the application. The MergeView
      class is a subclass of View and contains as additional instance variable
      the list of views that were merged. As an example if the group denoted
      by view <literal>V1:(p,q,r,s,t)</literal> split into subgroups
      <literal>V2:(p,q,r)</literal> and <literal>V2:(s,t)</literal> , the
      merged view might be <literal>V3:(p,q,r,s,t)</literal> . In this case
      the MergeView would contains a list of 2 views:
      <literal>V2:(p,q,r)</literal> and <literal>V2:(s,t)</literal> .</para>
    </section>
  </section>


  <section>
    <title>JChannel</title>

    <para>In order to join a group and send messages, a process has to create
    a channel. A channel is like a socket. When a client connects to a
    channel, it gives the the name of the group it would like to join. Thus, a
    channel is (in its connected state) always associated with a particular
    group. The protocol stack takes care that channels with the same group
    name find each other: whenever a client connects to a channel given group
    name G, then it tries to find existing channels with the same name, and
    joins them, resulting in a new view being installed (which contains the
    new member). If no members exist, a new group will be created.</para>

    <para>A state transition diagram for the major states a channel can assume
    are shown in <xref linkend="ChannelStatesFig" /> .</para>

    <figure id="ChannelStatesFig">
      <title>Channel states</title>

      <graphic align="center" fileref="images/ChannelStates.png" format="PNG" />
    </figure>

    <para>When a channel is first created, it is in the unconnected state. An
    attempt to perform certain operations which are only valid in the
    connected state (e.g. send/receive messages) will result in an exception.
    After a successful connection by a client, it moves to the connected
    state. Now channels will receive messages, views and suspicions from other
    members and may send messages to other members or to the group. Getting
    the local address of a channel is guaranteed to be a valid operation in
    this state (see below). When the channel is disconnected, it moves back to
    the unconnected state. Both a connected and unconnected channel may be
    closed, which makes the channel unusable for further operations. Any
    attempt to do so will result in an exception. When a channel is closed
    directly from a connected state, it will first be disconnected, and then
    closed.</para>

    <para>The methods available for creating and manipulating channels are
    discussed now.</para>

    <section>
      <title>Creating a channel</title>

      <para>
          A channel can be created in two ways: an instance of a subclass of
          <classname>Channel</classname> is created directly using its public
          constructor (e.g. <methodname>new JChannel()</methodname> ), or a
          channel factory is created, which -- upon request -- creates instances
          of channels. We will only look at the first method of creating channel:
          by direct instantiation.
      </para>

        <para>
            The public constructor of <classname>JChannel</classname> looks as follows:
        </para>

      <screen>
          public JChannel(String props) throws ChannelException {}
      </screen>

        <para>It creates an instance of <classname>JChannel</classname> . The
            <parameter>props</parameter> argument points to an XML file containing the configuration
            of the protocol stack to be used. This can be a String, but there are also other constructors which
            take for example a DOM element or a URL (more on this later).
        </para>

      <para>If the props argument is null, the default properties will be
      used. An exception will be thrown if the channel cannot be created.
      Possible causes include protocols that were specified in the property
      argument, but were not found, or wrong parameters to protocols.</para>


        <para>For example, the Draw demo can be launched as follows:</para>

        <screen>
          java org.javagroups.demos.Draw -props file:/home/bela/udp.xml
        </screen>

        <para>or</para>

        <screen>
          java org.javagroups.demos.Draw -props http://www.jgroups.org/udp.xml
        </screen>

        <para>
            In the latter case, an application downloads its protocol stack
            specification from a server, which allows for central administration
            of application properties.
        </para>
          <para>
              A sample XML configuration looks like this (edited from udp.xml):
          </para>
          <screen>
              &lt;config&gt;
                  &lt;UDP
                       mcast_addr="${jgroups.udp.mcast_addr:228.10.10.10}"
                       mcast_port="${jgroups.udp.mcast_port:45588}"
                       discard_incompatible_packets="true"
                       max_bundle_size="60000"
                       max_bundle_timeout="30"
                       ip_ttl="${jgroups.udp.ip_ttl:2}"
                       enable_bundling="true"
                       thread_pool.enabled="true"
                       thread_pool.min_threads="1"
                       thread_pool.max_threads="25"
                       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"/&gt;
                  &lt;PING timeout="2000"
                          num_initial_members="3"/&gt;
                  &lt;MERGE2 max_interval="30000"
                          min_interval="10000"/&gt;
                  &lt;FD_SOCK/&gt;
                  &lt;FD timeout="10000" max_tries="5" /&gt;
                  &lt;VERIFY_SUSPECT timeout="1500"  /&gt;
                  &lt;BARRIER /&gt;
                  &lt;pbcast.NAKACK
                                 use_mcast_xmit="false" gc_lag="0"
                                 retransmit_timeout="300,600,1200,2400,4800"
                                 discard_delivered_msgs="true"/&gt;
                  &lt;UNICAST timeout="300,600,1200,2400,3600"/&gt;
                  &lt;pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
                                 max_bytes="400000"/&gt;
                  &lt;VIEW_SYNC avg_send_interval="60000"   /&gt;
                  &lt;pbcast.GMS print_local_addr="true" join_timeout="3000"
                              view_bundling="true"/&gt;
                  &lt;FC max_credits="20000000"
                                  min_threshold="0.10"/&gt;
                  &lt;FRAG2 frag_size="60000"  /&gt;
                  &lt;pbcast.STATE_TRANSFER  /&gt;
              &lt;/config&gt;
          </screen>

          <para>
              A stack is wrapped by &lt;config&gt; and &lt;/config&gt; elements and lists all protocols from
              bottom (UDP) to top (STATE_TRANSFER). Each element defines one protocol.
          </para>

          <para>Each protocol is
              implemented as a Java class. When a protocol stack is created
              based on the above XML configuration, the first element ("UDP") becomes the
              bottom-most layer, the second one will be placed on the first, etc: the
              stack is created from the bottom to the top.
          </para>
          <para>
              Each element has to be the name of a Java class
              that resides in the <classname>org.jgroups.stack.protocols</classname>
              package. Note that only the base name has to be given, not the fully
              specified class name (<classname>UDP</classname> instead of
              <classname>org.jgroups.stack.protocols.UDP</classname>). If the
              protocol class is not found, JGroups assumes that the name given is a
              fully qualified classname and will therefore try to instantiate that
              class. If this does not work an exception is thrown. This allows for
              protocol classes to reside in different packages altogether, e.g. a
              valid protocol name could be
              <classname>com.sun.eng.protocols.reliable.UCAST</classname> .
          </para>

          <para>Each layer may have zero or more arguments, which are specified as
              a list of name/value pairs in parentheses directly after the protocol name.
              In the example above, UDP is configured with some options, one of them being the
              IP multicast address (mcast_addr) which is set to 228.10.10.10, or to the value of
              the system property jgroups.udp.mcast_addr, if set.
          </para>

          <para><emphasis>Note that all members in a group have to have the same
              protocol stack.</emphasis></para>


        <section>
            <title>Programmatic creation</title>
            <para>
                Usually, channels are created by passing the name of an XML configuration file to the JChannel() constructor.
                On top of this declarative configuration, JGroups provides an API to create a channel programmatically.
                The way to do this is to first create a JChannel, then an instance of ProtocolStack, then add all desired
                protocols to the stack and finally calling init() on the stack to set it up. The rest, e.g. calling
                JChannel.connect() is the same as with the declarative creation.
            </para>
            <para>
                An example of how to programmatically create a channel is shown below (copied from ProgrammaticChat):
                <screen>
     JChannel ch=new JChannel(false);         // 1
     ProtocolStack stack=new ProtocolStack(); // 2
     ch.setProtocolStack(stack);              // 3
     stack.addProtocol(new UDP().setValue("bind_addr", InetAddress.getByName("192.168.1.5")))
             .addProtocol(new PING())
             .addProtocol(new MERGE2())
             .addProtocol(new FD_SOCK())
             .addProtocol(new FD_ALL().setValue("timeout", 12000).setValue("interval", 3000))
             .addProtocol(new VERIFY_SUSPECT())
             .addProtocol(new BARRIER())
             .addProtocol(new NAKACK())
             .addProtocol(new UNICAST2())
             .addProtocol(new STABLE())
             .addProtocol(new GMS())
             .addProtocol(new UFC())
             .addProtocol(new MFC())
             .addProtocol(new FRAG2());       // 4
     stack.init();                            // 5

     ch.setReceiver(new ReceiverAdapter() {
         public void viewAccepted(View new_view) {
             System.out.println("view: " + new_view);
         }

         public void receive(Message msg) {
             System.out.println(msg.getObject() + " [" + msg.getSrc() + "]");
         }
     });

     ch.connect("ChatCluster");

     for(;;) {
         String line=Util.readStringFromStdin(": ");
         ch.send(null, null, line);
     }
                </screen>
            </para>
            <para>
                First a JChannel is created. The 'false' argument tells the channel not to create a ProtocolStack. This
                is needed because we will create one ourselves later (2) and set it in the channel (3).
            </para>
            <para>
                Next, all protocols are added to the stack. Note that the order is from bottom (transport protocol) to
                top. So UDP as transport is added first, then PING and so on, until FRAG2, which is the top protocol.
                Every protocol can be configured via setters, but there is also a generic setValue(String attr_name,
                Object value), which can be used to configure protocols as well, as shown in the example.
            </para>
            <para>
                Once the stack is configured, we call ProtocolStack.init() to link all protocols correctly and to call
                init() in every protocol instance. After this, the channel is ready to be used and all subsequent
                actions (e.g. connect()) can be executed. When the init() method returns, we have essentially the
                equivalent of new JChannel(config_file).
            </para>
        </section>



    </section>





      <section id="SettingOptions">
          <title>Setting options</title>

          <para>
              A number of options can be set in a channel. To do so, the following method is used:
              <screen>
              public void setOpt(int option, Object value);
              </screen>
          </para>

      <para>Arguments are the options number and a value. The following
      options are currently recognized:</para>

      <variablelist>
        <varlistentry>
          <term><constant>Channel.BLOCK</constant></term>

          <listitem>
            <para>The argument is a boolean object. If true, block messages will be received.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><constant>Channel.LOCAL</constant></term>

          <listitem>
            <para>Local delivery. The argument is a boolean value. If set to
            true, a member will receive all messages it sent to itself.
            Otherwise, all messages sent by itself will be discarded. This
            option allows to send messages to the group, without receiving a
            copy. Default is true (members will receive their own copy of
            messages multicast to the group).</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><constant>Channel.AUTO_RECONNECT</constant></term>

          <listitem>
            <para>When set to true, a shunned channel will leave the group and
            then try to automatically re-join. Default is false. Note that in 2.8, shunning has been removed, therefore
            this option has been deprecated.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><constant>Channel.AUTO_GETSTATE</constant></term>

          <listitem>
            <para>When set to true a shunned channel, after reconnection, will
            attempt to fetch the state from the coordinator. This requires
            AUTO_RECONNECT to be true as well. Default is false. Note that in 2.8, shunning has been removed, therefore
            this option has been deprecated.</para>
          </listitem>
        </varlistentry>
      </variablelist>

      <para>The equivalent method to get options is
      <methodname>getOpt()</methodname>:

      <screen>
          public Object getOpt(int option);
      </screen>
      </para>

      <para>Given an option, the current value of the option is
      returned.</para>

          <note>
              <title>Deprecating options in 3.0</title>

              <para>
                  Most of the options (except LOCAL) have been deprecated in 2.6.x and will be removed in 3.0.
              </para>
          </note>

    </section>

    <section>
        <title>Giving the channel a logical name</title>
        <para>
            A channel can be given a logical name which is then used instead of the channel's address. A logical name
            might show the function of a channel, e.g. "HostA-HTTP-Cluster", which is more legible than a UUID
            3c7e52ea-4087-1859-e0a9-77a0d2f69f29.
        </para>
        <para>
            For example, when we have 3 channels, using logical names we might see a view "{A,B,C}", which is nicer than
            "{56f3f99e-2fc0-8282-9eb0-866f542ae437, ee0be4af-0b45-8ed6-3f6e-92548bfa5cde, 9241a071-10ce-a931-f675-ff2e3240e1ad} !"
        </para>
        <para>
            If no logical name is set, JGroups generates one, using the hostname and a random number, e.g. linux-3442.
            If this is not desired and the UUIDs should be shown, use system property -Djgroups.print_uuids=true.
        </para>
        <para>
            The logical name can be set using:
            <screen>
               public void setName(String logical_name);
            </screen>
        </para>
        <para>
            This should be done before connecting a channel. Note that the logical name stays with a channel until
            the channel is destroyed, whereas a UUID is created on each connection.
        </para>

        <para>
            When JGroups starts, it prints the logical name and the associated physical address(es):
            <screen>
            -------------------------------------------------------------------
            GMS: address=mac-53465, cluster=DrawGroupDemo, physical address=192.168.1.3:49932
            -------------------------------------------------------------------
            ** View=[mac-53465|0] [mac-53465]
            </screen>

            The logical name is mac-53465 and the physical address is 192.168.1.3:49932. The UUID is not shown here.
        </para>
    </section>

    <section>
        <title>Generating custom addresses</title>
        <para>
            Since 2.12 address generation is pluggable. This means that an application can determine what kind of
            addresses it uses. The default address type is UUID, and since some protocols use UUID, it is recommended
            to provide custom classes as <emphasis>subclasses of UUID</emphasis>.
        </para>
        <para>
            This can be used to for example pass additional data around with an address, for example information about
            the location of the node to which the address is assigned. Note that methods equals(), hashCode() and
            compare() of the UUID super class should not be changed.
        </para>
        <para>
            To use custom addresses, the following things have to be done:
            <itemizedlist>
                <listitem>Write an implementation of org.jgroups.stack.AddressGenerator</listitem>
                <listitem>For any class CustomAddress, it will need to get registered with the ClassConfigurator
                in order to marshal it correctly:
                    <screen>
        class CustomAddress extends UUID {
            static {
                ClassConfigurator.add((short)8900, CustomAddress.class);
            }
        }
                    </screen>
                    Note that the ID should be chosen such that it doesn't collide with any IDs defined in
                    jg-magic-map.xml.
                </listitem>
                <listitem>Set the address generator in JChannel: setAddressGenerator(AddressGenerator). This
                    has to be done <emphasis>before</emphasis> the channel is connected</listitem>
            </itemizedlist>
        </para>
        <para>
            An example of a subclass is org.jgroups.util.PayloadUUID.
        </para>
    </section>

    <section>
      <title>Connecting to a channel</title>

      <para>When a client wants to join a group, it
      <emphasis>connects</emphasis> to a channel giving the name of the group
      to be joined:</para>

      <screen>
           public void connect(String clustername) throws ChannelClosed;
      </screen>

      <para>The cluster name is a string, naming the cluster to be joined. All
      channels that are connected to the same name form a cluster.
      Messages multicast on any channel in the cluster will be received by all
      members (including the one who sent it <footnote>
          <para>Local delivery can be turned on/off using
          <methodname>setOpt()</methodname> .</para>
        </footnote> ).</para>

      <para>The method returns as soon as the group has been joined
      successfully. If the channel is in the closed state (see <xref
      linkend="ChannelStatesFig" /> ), an exception will be thrown. If there
      are no other members, i.e. no other member has connected to a group with
      this name, then a new group is created and the member joined. The first
      member of a group becomes its <emphasis>coordinator</emphasis> . A
      coordinator is in charge of multicasting new views whenever the
      membership changes <footnote>
          <para>This is managed internally however, and an application
          programmer does not need to be concerned about it.</para>
        </footnote> .</para>            
      
    </section>
    
    <section>
          <title>Connecting to a channel and getting the state in one operation</title>
          <para>
	          Clients can also join a cluster group and fetch cluster state in one operation. 
	          The best way to conceptualize connect and fetch state connect method is to 
	          think of it as an invocation of regular connect and getstate methods executed in 
	          succession. However, there are several advantages of using connect and fetch state 
	          connect method over regular connect. First of all, underlying message exchange is 
	          heavily optimized, especially if the flush protocol is used in the stack. But more 
	          importantly, from clients perspective, connect and join operations become one atomic 
	          operation.          	        
		      </para>  
		      
		      <screen>
		      public void connect(string cluster_name, address target,
                                  string state_id, long timeout)
                          throws ChannelException;
		      </screen>
		      
		      <para>
		      Just as in regular connect method cluster name represents a cluster to be joined. 
		      Address parameter indicates a cluster member to fetch state from. Null address parameter 
		      indicates that state should be fetched from the cluster coordinator. If state should be fetched 
		      from a particular member other than coordinator clients can provide an address of that member. 
		      State id used for partial state transfer while timeout bounds entire join and fetch operation.        
      </para>
    </section>

    <section>
      <title>Getting the local address and the group name</title>

      <para>Method <methodname>getLocalAddress()</methodname> returns the
      local address of the channel<footnote>
              Since 2.8 the method is <methodname>getAddress()</methodname>
      </footnote>. In the case of
      <classname>JChannel</classname> , the local address is generated by the
      bottom-most layer of the protocol stack when the stack is connected to.
      That means that -- depending on the channel implementation -- the local
      address may or may not be available when a channel is in the unconnected
      state.</para>

      <screen>
         public Address getLocalAddress(); // use getAddress() with 2.8.0+
      </screen>

      <para>Method <methodname>getClusterName()</methodname> returns the name
      of the cluster in which the channel is a member:</para>

      <screen>
          public String getClusterName();
      </screen>

      <para>Again, the result is undefined if the channel is in the
      unconnected or closed state.</para>
    </section>

    <section>
      <title>Getting the current view</title>

      <para>The following method can be used to get the current view of a
      channel:</para>

      <screen>
         public View getView();
      </screen>

      <para>This method does <emphasis>not</emphasis> retrieve a new view
      (message) from the channel, but only returns the current view of the
      channel. The current view is updated every time a view message is
      received: when method <methodname>receive()</methodname> is called, and
      the return value is a view, before the view is returned, it will be
      installed in the channel, i.e. it will become the current view.</para>

      <para>Calling this method on an unconnected or closed channel is
      implementation defined. A channel may return null, or it may return the
      last view it knew of.</para>
    </section>

    <section>
      <title>Sending a message</title>

      <para>Once the channel is connected, messages can be sent using the
      <methodname>send()</methodname> methods:</para>

      <screen>
         public void send(Message msg) throws ChannelNotConnected, ChannelClosed;
         public void send(Address dst, Address src, Object obj)
                          throws ChannelNotConnected, ChannelClosed;
      </screen>

      <para>The first <methodname>send()</methodname> method has only one
      argument, which is the message to be sent. The message's destination
      should either be the address of the receiver (unicast) or null
      (multicast). When it is null, the message will be sent to all members of
      the group (including itself). The source address may be null; if it is,
      it will be set to the channel's address (so that recipients may generate
      a response and send it back to the sender).</para>

      <para>The second <methodname>send()</methodname> method is a helper
      method and uses the former method internally. It requires the address of
      receiver and sender and an object (which has to be serializable),
      constructs a Message and sends it.</para>

      <para>If the channel is not connected, or was closed, an exception will
      be thrown upon attempting to send a message.</para>

      <para>Here's an example of sending a (multicast) message to all members
      of a group:

      <screen>
          Map data; // any serializable data
          try {
              channel.send(null, null, data);
          }
          catch(Exception ex) {
              // handle errors
          }
      </screen>
      </para>

      <para>The null value as destination address means that the message will
      be sent to all members in the group. The sender's address will be filled
      in by the bottom-most protocol. The payload is a hashmap, which will
      be serialized into the message's buffer and unserialized at the
      receiver's end. Alternatively, any other means of generating a byte
      buffer and setting the message's buffer to it (e.g. using
      Message.setBuffer()) would also work.</para>

      <para>Here's an example of sending a (unicast) message to the first
      member (coordinator) of a group:

      <screen>
          Map data;
          try {
              Address receiver=channel.getView().getMembers().first();
              channel.send(receiver, null, data);
          }
          catch(Exception ex) {
              // handle errors
          }
      </screen>
      </para>

      <para>It creates a Message with a specific address for the receiver (the
      first member of the group). Again, the sender's address can be left null
      as it will be filled in by the bottom-most protocol.</para>
    </section>

    <section>
      <title>Receiving a message</title>

      <para>Method <methodname>receive()</methodname> is used to receive
      messages, views, suspicions and blocks:</para>

      <screen>
         public Object receive(long timeout) throws ChannelNotConnected,
                                                  ChannelClosed, Timeout;
      </screen>

      <para>A channel receives messages asynchronously from the network and
      stores them in a queue. When receive() is called, the next available
      message from the top of that queue is removed and returned. When there
      are no messages on the queue, the method will block. If
      <parameter>timeout</parameter> is greater than 0, it will wait the
      specified number of milliseconds for a message to be received, and throw
      a <classname>TimeoutException</classname> exception if none was received
      during that time. If the timeout is 0 or negative, the method will wait
      indefinitely for the next available message.</para>

      <para>Depending on the channel options (see <xref
      linkend="SettingOptions" /> ), the following types of objects may be
      received:</para>

      <variablelist>
        <varlistentry>
          <term>Message</term>

          <listitem>
            <para>A regular message. To send a response to the sender, a new
            message can be created. Its destination address would be the
            received message's source address. Method
            <methodname>Message.makeReply()</methodname> is a helper method to
            create a response.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>View</term>

          <listitem>
            <para>A view change, signalling that a member has joined, left or
            crashed. The application may or may not perform some action upon
            receiving a view change (e.g. updating a GUI object of the
            membership, or redistributing a load-balanced collaborative task
            to all members). Note that a longer action, or any action that
            blocks should be performed in a separate thread. A
            <classname>MergeView</classname> will be received when 2 or more
            subgroups merged into one (see <xref linkend="MergeView" /> for
            details). Here, a possible state merge by the application needs to
            be done in a separate thread.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>SuspectEvent</term>

          <listitem>
            <para>Notification of a member that is suspected. Method
            <methodname>SuspectEvent.getMember()</methodname> retrieves the
            address of the suspected member. Usually this message will be
            followed by a view change.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>BlockEvent</term>

          <listitem>
            <para>The application has to stop sending messages. When the application
            has stopped sending messages, it needs to acknowledge this message
            with a <methodname>Channel.blockOk()</methodname> method.</para>

            <para>
            The BlockEvent reception can be used to complete pending tasks, e.g. send pending
            messages, but once Channel.blockOk() has been called, all threads that send messages
            (calling Channel.send() or Channel.down()) will be blocked until FLUSH unblocks them.
            </para>
          </listitem>
        </varlistentry>


          <varlistentry>
              <term>UnblockEvent</term>

              <listitem>
                  <para>The application can resume sending messages. Any previously messages blocked by FLUSH
                  will be unblocked; when the UnblockEvent is received the channel has already been unblocked.</para>
              </listitem>
          </varlistentry>

        <varlistentry>
          <term>GetStateEvent</term>

          <listitem>
            <para>Received when the application's current state should be
            saved (for a later state transfer. A <emphasis>copy</emphasis> of
            the current state should be made (possibly wrapped in a
            <methodname>synchronized</methodname> statement and returned
            calling method <methodname>Channel.returnState()</methodname> . If
            state transfer events are not enabled on the channel (default),
            then this event will never be received. This message will only be
            received with the Virtual Synchrony suite of protocols (see the
            Programmer's Guide).</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>StreamingGetStateEvent</term>

          <listitem>
            <para>Received when the application's current state should be
            provided to a state requesting group member. If state transfer
            events are not enabled on the channel (default), or if channel is
            not configured with pbcast.STREAMING_STATE_TRANSFER then this
            event will never be received. </para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>SetStateEvent</term>

          <listitem>
            <para>Received as response to a
            <methodname>getState(s)</methodname> method call. The argument
            contains the state of a single member ( <type>byte[]</type> ) or
            of all members ( <classname>Vector</classname> ). Since the state
            of a single member could also be a vector, the interpretation of
            the argument is left to the application.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>StreamingSetStateEvent</term>

          <listitem>
            <para>Received at state requesting member when the state
            InputStream becomes ready for reading. If state transfer events
            are not enabled on the channel (default), or if channel is not
            configured with pbcast.STREAMING_STATE_TRANSFER then this event
            will never be received. </para>
          </listitem>
        </varlistentry>
      </variablelist>

      <para>The caller has to check the type of the object returned. This can
      be done using the <methodname>instanceof</methodname> operator, as
      follows:
      <screen>
          Object obj=channel.receive(0); // wait forever
          if(obj instanceof Message)
              Message msg=(Message)obj;
          else if(obj instanceof View)
              View v=(View)obj;
          else
              ; // don't handle suspicions or blocks
      </screen>
      </para>

      <para>If for example views, suspicions and blocks are disabled, then the
      caller is guaranteed to only receive return values of type
      <classname>Message</classname> . In this case, the return value can be
      cast to a <classname>Message</classname> directly, without using the
      <methodname>instanceof</methodname> operator.</para>

      <para>If the channel is not connected, or was closed, a corresponding
      exception will be thrown.</para>

      <para>The example below shows how to retrieve the "Hello world" string
      from a message:
      <screen>
          Message msg; // received above
          try {
              String s=(String)msg.getObject(); // error if obj not Serializable
              // alternative: s=new String(msg.getBuffer());
          }
          catch(Exception ex) {
              // handle errors, e.g. casting error above)
          }
      </screen>
      </para>

      <para>The Message.getObject() method retrieves the message's byte
      buffer, converts it into a (serializable) object and returns the
      object.</para>
    </section>

    <section>
      <title>Using a Receiver to receive messages</title>

      <para>Instead of pulling messages from a channel in an application
          thread, a Receiver can be registered with a channel. This is the preferred and recommended way of receiving
          messages. In 3.0, the receive() method will be removed from JChannel.
          All received messages, view changes and state transfer requests will invoke callbacks
          on the registered Receiver:
      <screen>
          JChannel ch=new JChannel();
          ch.setReceiver(new ExtendedReceiverAdapter() {
              public void receive(Message msg) {
                  System.out.println("received message " + msg);
              }
              public void viewAccepted(View new_view) {
                  System.out.println("received view " + new_view);
              }
          });
          ch.connect("bla");
      </screen>
        </para>

      <para>The <classname>ExtendedReceiverAdapter</classname> class
      implements all callbacks of ExtendedReceiver with no-ops, in the example
      above we override receive() and viewAccepted().</para>

      <para>The advantage of using a Receiver is that the application doesn't
      have to waste 1 thread for pulling messages out of a channel. In
      addition, the channel doesn't have to maintain an (unbounded) queue of
      messages/views, which can quickly get large if the receiver cannot
      process messages fast enough, and the sender keeps sending
      messages.</para>
        <note>
            Note that the Channel.receive() method has been deprecated, and will be removed in 3.0. Use the Receiver
            interface instead and register as a Receiver with Channel.setReceiver(Receiver r).
        </note>
    </section>

    <section>
      <title>Peeking at a message</title>

      <para>Instead of removing the next available message from the channel,
      <methodname>peek()</methodname> just returns a reference to the next
      message, but does not remove it. This is useful when one has to check
      the type of the next message, e.g. whether it is a regular message, or a
      view change. The signature of this method is not shown here, it is the
      same as for <methodname>receive()</methodname> .</para>
        <note>
            The peek() method has also been deprecated, and will be removed in 3.0.
        </note>
    </section>

    <section id="GetState">
      <title>Getting the group's state</title>

      <para>A newly joined member may wish to retrieve the state of the group
      before starting work. This is done with
      <methodname>getState()</methodname>. This method returns the state of
      one member (in most cases, of the oldest member, the coordinator). It
      returns true or false, depending on whether a valid state could be
      retrieved. For example, if a member is a singleton, then calling this
      method would always return false <footnote>
          <para>A member will <emphasis>never</emphasis> retrieve the state
          from itself !</para>
        </footnote> .</para>

      <para>The actual state is returned as the return value of one of the
      subsequent <methodname>receive()</methodname> calls, in the form of a
      <classname>SetStateEvent</classname> object. If
      <methodname>getState()</methodname> returned true, then a valid state
      (non-null) will be returned, otherwise a null state will be returned.
      Alternatively if an application uses MembershipListener (see <xref
      linkend="MembershipListener" /> ) instead of pulling messages from a
      channel, the <methodname>getState()</methodname> method will be invoked
      and a copy of the current state should be returned. By the same token,
      setting a state would be accomplished by JGroups calling the
      <methodname>setState()</methodname> method of the state fetcher.</para>

      <para>The reason for not directly returning the state as a result of
      <methodname>getState()</methodname> is that the state has to be returned
      in the correct position relative to other messages. Returning it
      directly would violate the FIFO properties of a channel, and state
      transfer would not be correct.</para>

      <para>The following code fragment shows how a group member participates
      in state transfers:
      <screen>
          channel=new JChannel();
          channel.connect("TestChannel");
          boolean rc=channel.getState(null, 5000);

          ...

          Object state, copy;
          Object ret=channel.receive(0);
          if(ret instanceof Message)
              ;
          else if(ret instanceof GetStateEvent) {
              // make a copy so that other msgs don't change the state
              copy=copyState(state);
              channel.returnState(Util.objectToByteBuffer(copy));
          }
          else if(ret instanceof SetStateEvent) {
              SetStateEvent e=(SetStateEvent)ret;
              state=e.getArg();
          }
      </screen>
      </para>


      <para>A JChannel has to be created whose stack includes the
      <constant>STATE_TRANSFER</constant> or
      <constant>pbcast.STATE_TRANSFER</constant> protocols (see <xref
      linkend="user-advanced" /> ). Method <methodname>getState()</methodname>
      subsequently asks the channel to return the current state. If there is a
      current state (there may not be any other members in the group !), then
      true is returned. In this case, one of the subsequent
      <methodname>receive()</methodname> method invocations on the channel
      will return a <classname>SetStateEvent</classname> object which contains
      the current state. In this case, the caller sets its state to the one
      received from the channel.</para>

      <para>Method <methodname>receive()</methodname> might return a
      <classname>GetStateEvent</classname> object, requesting the state of the
      member to be returned. In this case, <emphasis>a copy of the current
      state should be made</emphasis> and returned using
      <methodname>JChannel.returnState()</methodname> . It is important to a)
      synchronize access to the state when returning it since other accesses
      may modify it while it is being returned and b) make a copy of the state
      since other accesses after returning the state may still be able to
      modify it ! This is possible because the state is not immediately
      returned, but travels down the stack (in the same address space), and a
      reference to it could still alter it.</para>
    </section>

    <section>
      <title>Getting the state with a Receiver</title>

      <para>As an alternative to handling the GetStateEvent and SetStateEvent
      events, and calling Channel.returnState(), a Receiver could be used. The
      example above would look like this:
      <screen>
          class MyReceiver extends ReceiverAdapter {
              final Map m=new HashMap();
              public byte[] getState() {
                  // so nobody else can modify the map while we serialize it
                  synchronized(m) {
                      byte[] state=Util.objectToByteBuffer(m);
                      return state;
                  }
              }

              public void setState(byte[] state) {
                  synchronized(m) {
                      Map new_m=(Map)Util.objectFromByteBuffer(state);
                      m.clear();
                      m.addAll(new_m);
                  }
              }
          }
          // use default props (has to include STATE_TRANSFER)
          channel=new JChannel();
          channel.setReceiver(new MyReceiver());
          channel.connect("TestChannel");
          boolean rc=channel.getState(null, 5000);
      </screen>
      </para>

      <para>In a group consisting of A,B and C, with D joining the group and
      calling Channel.getState(), the following sequence of callbacks happens:
      <itemizedlist>
          <listitem>
             D calls Channel.getState(). The state will be retrieved from the oldest member, A 
          </listitem>

          <listitem>
             A.MyReceiver.getState() is called. A returns a copy of its hashmap 
          </listitem>

          <listitem>
             D: getState() returns true 
          </listitem>

          <listitem>
             D.MyReceiver.setState() is called with the serialized state. D unserializes the state and sets it 
          </listitem>
        </itemizedlist></para>
    </section>

    <section id="PartialStateTransfer">
      <title>Partial state transfer</title>

      <para>Partial state transfer means that instead of transferring the
      entire state, we may want to transfer only a
      <emphasis>substate</emphasis>. For example, with HTTP session
      replication, a new node in a cluster may want to transfer only the state
      of a specific session, not <emphasis>all</emphasis> HTTP sessions. This
      can be done with either the pull or push model. The method to call would
      be Channel.getState(), including the ID of the substate (a string). In
      the pull model, GetStateEvent and SetStateEvent have an additional
      member, state_id, and in the push model, there are 2 additional
      getState() and setState() callbacks. The example below shows partial
      state transfer for the push model:
      <screen>
          class MyReceiver extends ExtendedReceiverAdapter {
              final Map m=new HashMap();

              public byte[] getState() {
                  return getState(null);
              }

              public byte[] getState(String substate_id) {
                  // so nobody can modify the map while we serialize it
                  synchronized(m) {
                      byte[] state=null;
                      if(substate_id == null) {
                          state=Util.objectToByteBuffer(m);
                      }
                      else {
                          Object value=m.get(substate_id);
                          if(value != null) {
                              return Util.objectToByteBuffer(value);
                          }
                      }
                      return state;
                  }
              }

              public void setState(byte[] state) {
                  setState(null, state);
              }

              public void setState(String substate_id, byte[] state) {
                  synchronized(m) {
                      if(substate_id != null) {
                          Object value=Util.objectFromByteBuffer(state);
                          m.put(substate_id, value);
                      }
                      else {
                          Map new_m=(Map)Util.objectFromByteBuffer(state);
                          m.clear();
                          m.addAll(new_m);
                      }
                  }
              }
          }

          // use default props (has to include pbcast.STATE_TRANSFER)
          channel=new JChannel();
          channel.setReceiver(new MyReceiver());
          channel.connect("TestChannel");
          boolean rc=channel.getState(null, "MyID", 5000);
      </screen>
      </para>

      <para>The example shows that the Channel.getState() method specifies the
      ID of the substate, in this case "MyID". The
      <methodname>getState(String substate_id)</methodname> method checks
      whether the substate ID is not null, and returns the substate pertaining
      to the ID, or the entire state if the substate_id is null. The same goes
      for setting the substate: if <methodname>setState(String substate_id,
      byte[] state)</methodname> has a non-null substate_id, only that part of
      the current state will be overwritten, otherwise (if null) the entire
      state will be overwritten.</para>
    </section>

    <section>
      <title>Streaming state transfer</title>

      <para>Streaming state transfer allows transfer of application (partial)
      state without having to load entire state into memory prior to sending
      it to a joining member. Streaming state transfer is especially useful if
      the state is very large (&gt;1Gb), and use of regular state transfer
      would likely result in OutOfMemoryException. Streaming state transfer
      was introduced in JGroups 2.4. JGroups channel has to be configured with
      either regular or streaming state transfer. The JChannel API that invokes
      state transfer (i.e. JChannel.getState(long timeout, Address member))
      remains the same. </para>

      <para>Streaming state transfer, just as regular byte based state
      transfer, can be used in both pull and push mode. Similarly to the
      current getState and setState methods of org.jgroups.MessageListener,
      the application interested in streaming state transfer in a push mode would
      implement streaming getState method(s) by sending/writing state through
      a provided OutputStream reference and setState method(s) by
      receiving/reading state through a provided InputStream reference. In
      order to use streaming state transfer in a push mode, existing
      ExtendedMessageListener has been expanded to include additional four
      methods:
      <screen>
         public interface ExtendedMessageListener {

             /*non-streaming callback methods ommitted for clarity*/
 
             void getState(OutputStream ostream);
             void getState(String state_id, OutputStream ostream);
             void setState(InputStream istream);
             void setState(String state_id, InputStream istream);
          }
      </screen>
      </para>

      <para>For a pull mode (when application uses channel.receive() to fetch
      events) two new event classes will be introduced:</para>

      <para><itemizedlist>
          <listitem>
            <para>StreamingGetStateEvent</para>
          </listitem>

          <listitem>
            <para>StreamingSetStateEvent</para>
          </listitem>
        </itemizedlist> These two events/classes are very similar to existing
      GetStateEvent and SetStateEvent but introduce a new field;
      StreamingGetStateEvent has an OutputStream and StreamingSetStateEvent
      has an InputStream.</para>

      <para>The following code snippet demonstrates how to pull events from a
      channel, processing StreamingGetStateEvent and sending hypothetical
      state through a provided OutputStream reference. Handling of
      StreamingSetStateEvent is analogous to this example:
          <screen>
          ...
          Object obj=channel.receive(0);
          if(obj instanceof StreamingGetStateEvent) {
              StreamingGetStateEvent evt=(StreamingGetStateEvent)obj;
              OutputStream oos = null;
              try {
                  oos=new ObjectOutputStream(evt.getArg());
                  oos.writeObject(state);
                  oos.flush();
              }
              catch (Exception e) {}
              finally {
                  try {
                      oos.close();
                  }
                  catch (IOException e) {
                      System.err.println(e);
                  }
              }
          }                 
          </screen>
      </para>

      <para>JGroups has a great flexibility with state transfer methodology by
      allowing application developers to implement both byte based and
      streaming based state transfers. Application can, for example, implement
      streaming and byte based state transfer callbacks and then interchange
      state transfer protocol in channel configuration to use either streaming
      or byte based state transfer. However, one cannot configure a channel
      with both state transfers at the same time and then in runtime choose
      which particular state transfer type to use.</para>
    </section>     
    
    <section>
      <title>Disconnecting from a channel</title>

      <para>Disconnecting from a channel is done using the following
      method:
          <screen>
          public void disconnect();
          </screen>
      </para>

      <para>It will have no effect if the channel is already in the
      disconnected or closed state. If connected, it will remove itself from
      the group membership. This is done (transparently for a channel user) by
      sending a leave request to the current coordinator. The latter will
      subsequently remove the channel's address from its local view and send
      the new view to all remaining members.</para>

      <para>After a successful disconnect, the channel will be in the
      unconnected state, and may subsequently be re-connected to.</para>
    </section>

    <section>
      <title>Closing a channel</title>

      <para>To destroy a channel instance (destroy the associated protocol
      stack, and release all resources), method
      <methodname>close()</methodname> is used:
        <screen>
         public void close();
        </screen>
        </para>

      <para>It moves the channel to the closed state, in which no further
      operations are allowed (most throw an exception when invoked on a closed
      channel). In this state, a channel instance is not considered used any
      longer by an application and -- when the reference to the instance is
      reset -- the channel essentially only lingers around until it is garbage
      collected by the Java runtime system.</para>
    </section>
  </section>
</chapter>