22
22
import static com .rabbitmq .stream .impl .Utils .noOpConsumer ;
23
23
import static java .lang .String .format ;
24
24
import static java .lang .String .join ;
25
+ import static java .util .Arrays .asList ;
25
26
import static java .util .concurrent .TimeUnit .SECONDS ;
27
+ import static java .util .stream .StreamSupport .stream ;
26
28
27
29
import com .rabbitmq .stream .AuthenticationFailureException ;
28
30
import com .rabbitmq .stream .ByteCapacity ;
83
85
import java .net .ConnectException ;
84
86
import java .net .InetSocketAddress ;
85
87
import java .net .SocketAddress ;
88
+ import java .nio .charset .Charset ;
86
89
import java .nio .charset .StandardCharsets ;
87
90
import java .time .Duration ;
88
- import java .util .ArrayList ;
89
- import java .util .Collections ;
90
- import java .util .HashMap ;
91
- import java .util .HashSet ;
92
- import java .util .List ;
93
- import java .util .Map ;
94
- import java .util .Objects ;
95
- import java .util .Set ;
91
+ import java .util .*;
96
92
import java .util .concurrent .ConcurrentHashMap ;
97
93
import java .util .concurrent .ConcurrentMap ;
98
94
import java .util .concurrent .CopyOnWriteArrayList ;
127
123
*/
128
124
public class Client implements AutoCloseable {
129
125
126
+ private static final Charset CHARSET = StandardCharsets .UTF_8 ;
130
127
public static final int DEFAULT_PORT = 5552 ;
131
128
public static final int DEFAULT_TLS_PORT = 5551 ;
132
129
static final OutboundEntityWriteCallback OUTBOUND_MESSAGE_WRITE_CALLBACK =
@@ -446,12 +443,7 @@ int maxFrameSize() {
446
443
}
447
444
448
445
private Map <String , String > peerProperties () {
449
- int clientPropertiesSize = 4 ; // size of the map, always there
450
- if (!clientProperties .isEmpty ()) {
451
- for (Map .Entry <String , String > entry : clientProperties .entrySet ()) {
452
- clientPropertiesSize += 2 + entry .getKey ().length () + 2 + entry .getValue ().length ();
453
- }
454
- }
446
+ int clientPropertiesSize = mapSize (this .clientProperties );
455
447
int length = 2 + 2 + 4 + clientPropertiesSize ;
456
448
int correlationId = correlationSequence .incrementAndGet ();
457
449
try {
@@ -460,13 +452,7 @@ private Map<String, String> peerProperties() {
460
452
bb .writeShort (encodeRequestCode (COMMAND_PEER_PROPERTIES ));
461
453
bb .writeShort (VERSION_1 );
462
454
bb .writeInt (correlationId );
463
- bb .writeInt (clientProperties .size ());
464
- for (Map .Entry <String , String > entry : clientProperties .entrySet ()) {
465
- bb .writeShort (entry .getKey ().length ())
466
- .writeBytes (entry .getKey ().getBytes (StandardCharsets .UTF_8 ))
467
- .writeShort (entry .getValue ().length ())
468
- .writeBytes (entry .getValue ().getBytes (StandardCharsets .UTF_8 ));
469
- }
455
+ writeMap (bb , this .clientProperties );
470
456
OutstandingRequest <Map <String , String >> request = outstandingRequest ();
471
457
outstandingRequests .put (correlationId , request );
472
458
channel .writeAndFlush (bb );
@@ -540,7 +526,7 @@ private SaslAuthenticateResponse sendSaslAuthenticate(
540
526
bb .writeShort (VERSION_1 );
541
527
bb .writeInt (correlationId );
542
528
bb .writeShort (saslMechanism .getName ().length ());
543
- bb .writeBytes (saslMechanism .getName ().getBytes (StandardCharsets . UTF_8 ));
529
+ bb .writeBytes (saslMechanism .getName ().getBytes (CHARSET ));
544
530
if (challengeResponse == null ) {
545
531
bb .writeInt (-1 );
546
532
} else {
@@ -570,7 +556,7 @@ private Map<String, String> open(String virtualHost) {
570
556
bb .writeShort (VERSION_1 );
571
557
bb .writeInt (correlationId );
572
558
bb .writeShort (virtualHost .length ());
573
- bb .writeBytes (virtualHost .getBytes (StandardCharsets . UTF_8 ));
559
+ bb .writeBytes (virtualHost .getBytes (CHARSET ));
574
560
OutstandingRequest <OpenResponse > request = outstandingRequest ();
575
561
outstandingRequests .put (correlationId , request );
576
562
channel .writeAndFlush (bb );
@@ -612,7 +598,7 @@ private void sendClose(short code, String reason) {
612
598
bb .writeInt (correlationId );
613
599
bb .writeShort (code );
614
600
bb .writeShort (reason .length ());
615
- bb .writeBytes (reason .getBytes (StandardCharsets . UTF_8 ));
601
+ bb .writeBytes (reason .getBytes (CHARSET ));
616
602
OutstandingRequest <Response > request = outstandingRequest ();
617
603
outstandingRequests .put (correlationId , request );
618
604
channel .writeAndFlush (bb );
@@ -662,10 +648,7 @@ public Response create(String stream) {
662
648
}
663
649
664
650
public Response create (String stream , Map <String , String > arguments ) {
665
- int length = 2 + 2 + 4 + 2 + stream .length () + 4 ;
666
- for (Map .Entry <String , String > argument : arguments .entrySet ()) {
667
- length = length + 2 + argument .getKey ().length () + 2 + argument .getValue ().length ();
668
- }
651
+ int length = 2 + 2 + 4 + 2 + stream .length () + mapSize (arguments );
669
652
int correlationId = correlationSequence .incrementAndGet ();
670
653
try {
671
654
ByteBuf bb = allocate (length + 4 );
@@ -674,14 +657,8 @@ public Response create(String stream, Map<String, String> arguments) {
674
657
bb .writeShort (VERSION_1 );
675
658
bb .writeInt (correlationId );
676
659
bb .writeShort (stream .length ());
677
- bb .writeBytes (stream .getBytes (StandardCharsets .UTF_8 ));
678
- bb .writeInt (arguments .size ());
679
- for (Map .Entry <String , String > argument : arguments .entrySet ()) {
680
- bb .writeShort (argument .getKey ().length ());
681
- bb .writeBytes (argument .getKey ().getBytes (StandardCharsets .UTF_8 ));
682
- bb .writeShort (argument .getValue ().length ());
683
- bb .writeBytes (argument .getValue ().getBytes (StandardCharsets .UTF_8 ));
684
- }
660
+ bb .writeBytes (stream .getBytes (CHARSET ));
661
+ writeMap (bb , arguments );
685
662
OutstandingRequest <Response > request = outstandingRequest ();
686
663
outstandingRequests .put (correlationId , request );
687
664
channel .writeAndFlush (bb );
@@ -696,6 +673,116 @@ public Response create(String stream, Map<String, String> arguments) {
696
673
}
697
674
}
698
675
676
+ Response createSuperStream (
677
+ String superStream ,
678
+ List <String > partitions ,
679
+ List <String > routingKeys ,
680
+ Map <String , String > arguments ) {
681
+ if (partitions .isEmpty () || routingKeys .isEmpty ()) {
682
+ throw new IllegalArgumentException (
683
+ "Partitions and routing keys of a super stream cannot be empty" );
684
+ }
685
+ if (partitions .size () != routingKeys .size ()) {
686
+ throw new IllegalArgumentException (
687
+ "Partitions and routing keys of a super stream must have "
688
+ + "the same number of elements" );
689
+ }
690
+ int length =
691
+ 2
692
+ + 2
693
+ + 4
694
+ + 2
695
+ + superStream .length ()
696
+ + collectionSize (partitions )
697
+ + collectionSize (routingKeys )
698
+ + mapSize (arguments );
699
+ int correlationId = correlationSequence .incrementAndGet ();
700
+ try {
701
+ ByteBuf bb = allocate (length + 4 );
702
+ bb .writeInt (length );
703
+ bb .writeShort (encodeRequestCode (COMMAND_CREATE_SUPER_STREAM ));
704
+ bb .writeShort (VERSION_1 );
705
+ bb .writeInt (correlationId );
706
+ bb .writeShort (superStream .length ());
707
+ bb .writeBytes (superStream .getBytes (CHARSET ));
708
+ writeCollection (bb , partitions );
709
+ writeCollection (bb , routingKeys );
710
+ writeMap (bb , arguments );
711
+ OutstandingRequest <Response > request = outstandingRequest ();
712
+ outstandingRequests .put (correlationId , request );
713
+ channel .writeAndFlush (bb );
714
+ request .block ();
715
+ return request .response .get ();
716
+ } catch (StreamException e ) {
717
+ outstandingRequests .remove (correlationId );
718
+ throw e ;
719
+ } catch (RuntimeException e ) {
720
+ outstandingRequests .remove (correlationId );
721
+ throw new StreamException (format ("Error while creating super stream '%s'" , superStream ), e );
722
+ }
723
+ }
724
+
725
+ Response deleteSuperStream (String superStream ) {
726
+ int length = 2 + 2 + 4 + 2 + superStream .length ();
727
+ int correlationId = correlationSequence .incrementAndGet ();
728
+ try {
729
+ ByteBuf bb = allocate (length + 4 );
730
+ bb .writeInt (length );
731
+ bb .writeShort (encodeRequestCode (COMMAND_DELETE_SUPER_STREAM ));
732
+ bb .writeShort (VERSION_1 );
733
+ bb .writeInt (correlationId );
734
+ bb .writeShort (superStream .length ());
735
+ bb .writeBytes (superStream .getBytes (CHARSET ));
736
+ OutstandingRequest <Response > request = outstandingRequest ();
737
+ outstandingRequests .put (correlationId , request );
738
+ channel .writeAndFlush (bb );
739
+ request .block ();
740
+ return request .response .get ();
741
+ } catch (StreamException e ) {
742
+ outstandingRequests .remove (correlationId );
743
+ throw e ;
744
+ } catch (RuntimeException e ) {
745
+ outstandingRequests .remove (correlationId );
746
+ throw new StreamException (format ("Error while deleting stream '%s'" , superStream ), e );
747
+ }
748
+ }
749
+
750
+ private static int collectionSize (Collection <String > elements ) {
751
+ return 4 + elements .stream ().mapToInt (v -> 2 + v .length ()).sum ();
752
+ }
753
+
754
+ private static int arraySize (String ... elements ) {
755
+ return 4 + collectionSize (asList (elements ));
756
+ }
757
+
758
+ private static int mapSize (Map <String , String > elements ) {
759
+ return 4
760
+ + elements .entrySet ().stream ()
761
+ .mapToInt (e -> 2 + e .getKey ().length () + 2 + e .getValue ().length ())
762
+ .sum ();
763
+ }
764
+
765
+ private static ByteBuf writeCollection (ByteBuf bb , Collection <String > elements ) {
766
+ bb .writeInt (elements .size ());
767
+ elements .forEach (e -> bb .writeShort (e .length ()).writeBytes (e .getBytes (CHARSET )));
768
+ return bb ;
769
+ }
770
+
771
+ private static ByteBuf writeArray (ByteBuf bb , String ... elements ) {
772
+ return writeCollection (bb , asList (elements ));
773
+ }
774
+
775
+ private static ByteBuf writeMap (ByteBuf bb , Map <String , String > elements ) {
776
+ bb .writeInt (elements .size ());
777
+ elements .forEach (
778
+ (key , value ) ->
779
+ bb .writeShort (key .length ())
780
+ .writeBytes (key .getBytes (CHARSET ))
781
+ .writeShort (value .length ())
782
+ .writeBytes (value .getBytes (CHARSET )));
783
+ return bb ;
784
+ }
785
+
699
786
ByteBuf allocate (ByteBufAllocator allocator , int capacity ) {
700
787
if (frameSizeCopped && capacity > this .maxFrameSize ()) {
701
788
throw new IllegalArgumentException (
@@ -729,7 +816,7 @@ public Response delete(String stream) {
729
816
bb .writeShort (VERSION_1 );
730
817
bb .writeInt (correlationId );
731
818
bb .writeShort (stream .length ());
732
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
819
+ bb .writeBytes (stream .getBytes (CHARSET ));
733
820
OutstandingRequest <Response > request = outstandingRequest ();
734
821
outstandingRequests .put (correlationId , request );
735
822
channel .writeAndFlush (bb );
@@ -748,23 +835,15 @@ public Map<String, StreamMetadata> metadata(String... streams) {
748
835
if (streams == null || streams .length == 0 ) {
749
836
throw new IllegalArgumentException ("At least one stream must be specified" );
750
837
}
751
- int length = 2 + 2 + 4 + 4 ; // API code, version, correlation ID, size of array
752
- for (String stream : streams ) {
753
- length += 2 ;
754
- length += stream .length ();
755
- }
838
+ int length = 2 + 2 + 4 + arraySize (streams ); // API code, version, correlation ID, array size
756
839
int correlationId = correlationSequence .incrementAndGet ();
757
840
try {
758
841
ByteBuf bb = allocate (length + 4 );
759
842
bb .writeInt (length );
760
843
bb .writeShort (encodeRequestCode (COMMAND_METADATA ));
761
844
bb .writeShort (VERSION_1 );
762
845
bb .writeInt (correlationId );
763
- bb .writeInt (streams .length );
764
- for (String stream : streams ) {
765
- bb .writeShort (stream .length ());
766
- bb .writeBytes (stream .getBytes (StandardCharsets .UTF_8 ));
767
- }
846
+ writeArray (bb , streams );
768
847
OutstandingRequest <Map <String , StreamMetadata >> request = outstandingRequest ();
769
848
outstandingRequests .put (correlationId , request );
770
849
channel .writeAndFlush (bb );
@@ -800,10 +879,10 @@ public Response declarePublisher(byte publisherId, String publisherReference, St
800
879
bb .writeByte (publisherId );
801
880
bb .writeShort (publisherReferenceSize );
802
881
if (publisherReferenceSize > 0 ) {
803
- bb .writeBytes (publisherReference .getBytes (StandardCharsets . UTF_8 ));
882
+ bb .writeBytes (publisherReference .getBytes (CHARSET ));
804
883
}
805
884
bb .writeShort (stream .length ());
806
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
885
+ bb .writeBytes (stream .getBytes (CHARSET ));
807
886
OutstandingRequest <Response > request = outstandingRequest ();
808
887
outstandingRequests .put (correlationId , request );
809
888
channel .writeAndFlush (bb );
@@ -1142,10 +1221,7 @@ public Response subscribe(
1142
1221
}
1143
1222
int propertiesSize = 0 ;
1144
1223
if (properties != null && !properties .isEmpty ()) {
1145
- propertiesSize = 4 ; // size of the map
1146
- for (Map .Entry <String , String > entry : properties .entrySet ()) {
1147
- propertiesSize += 2 + entry .getKey ().length () + 2 + entry .getValue ().length ();
1148
- }
1224
+ propertiesSize = mapSize (properties );
1149
1225
}
1150
1226
length += propertiesSize ;
1151
1227
int correlationId = correlationSequence .getAndIncrement ();
@@ -1157,20 +1233,14 @@ public Response subscribe(
1157
1233
bb .writeInt (correlationId );
1158
1234
bb .writeByte (subscriptionId );
1159
1235
bb .writeShort (stream .length ());
1160
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
1236
+ bb .writeBytes (stream .getBytes (CHARSET ));
1161
1237
bb .writeShort (offsetSpecification .getType ());
1162
1238
if (offsetSpecification .isOffset () || offsetSpecification .isTimestamp ()) {
1163
1239
bb .writeLong (offsetSpecification .getOffset ());
1164
1240
}
1165
1241
bb .writeShort (initialCredits );
1166
1242
if (properties != null && !properties .isEmpty ()) {
1167
- bb .writeInt (properties .size ());
1168
- for (Map .Entry <String , String > entry : properties .entrySet ()) {
1169
- bb .writeShort (entry .getKey ().length ())
1170
- .writeBytes (entry .getKey ().getBytes (StandardCharsets .UTF_8 ))
1171
- .writeShort (entry .getValue ().length ())
1172
- .writeBytes (entry .getValue ().getBytes (StandardCharsets .UTF_8 ));
1173
- }
1243
+ writeMap (bb , properties );
1174
1244
}
1175
1245
OutstandingRequest <Response > request = outstandingRequest ();
1176
1246
outstandingRequests .put (correlationId , request );
@@ -1205,9 +1275,9 @@ public void storeOffset(String reference, String stream, long offset) {
1205
1275
bb .writeShort (encodeRequestCode (COMMAND_STORE_OFFSET ));
1206
1276
bb .writeShort (VERSION_1 );
1207
1277
bb .writeShort (reference .length ());
1208
- bb .writeBytes (reference .getBytes (StandardCharsets . UTF_8 ));
1278
+ bb .writeBytes (reference .getBytes (CHARSET ));
1209
1279
bb .writeShort (stream .length ());
1210
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
1280
+ bb .writeBytes (stream .getBytes (CHARSET ));
1211
1281
bb .writeLong (offset );
1212
1282
channel .writeAndFlush (bb );
1213
1283
}
@@ -1230,9 +1300,9 @@ public QueryOffsetResponse queryOffset(String reference, String stream) {
1230
1300
bb .writeShort (VERSION_1 );
1231
1301
bb .writeInt (correlationId );
1232
1302
bb .writeShort (reference .length ());
1233
- bb .writeBytes (reference .getBytes (StandardCharsets . UTF_8 ));
1303
+ bb .writeBytes (reference .getBytes (CHARSET ));
1234
1304
bb .writeShort (stream .length ());
1235
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
1305
+ bb .writeBytes (stream .getBytes (CHARSET ));
1236
1306
OutstandingRequest <QueryOffsetResponse > request = outstandingRequest ();
1237
1307
outstandingRequests .put (correlationId , request );
1238
1308
channel .writeAndFlush (bb );
@@ -1271,9 +1341,9 @@ public long queryPublisherSequence(String publisherReference, String stream) {
1271
1341
bb .writeShort (VERSION_1 );
1272
1342
bb .writeInt (correlationId );
1273
1343
bb .writeShort (publisherReference .length ());
1274
- bb .writeBytes (publisherReference .getBytes (StandardCharsets . UTF_8 ));
1344
+ bb .writeBytes (publisherReference .getBytes (CHARSET ));
1275
1345
bb .writeShort (stream .length ());
1276
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
1346
+ bb .writeBytes (stream .getBytes (CHARSET ));
1277
1347
OutstandingRequest <QueryPublisherSequenceResponse > request = outstandingRequest ();
1278
1348
outstandingRequests .put (correlationId , request );
1279
1349
channel .writeAndFlush (bb );
@@ -1436,9 +1506,9 @@ public List<String> route(String routingKey, String superStream) {
1436
1506
bb .writeShort (VERSION_1 );
1437
1507
bb .writeInt (correlationId );
1438
1508
bb .writeShort (routingKey .length ());
1439
- bb .writeBytes (routingKey .getBytes (StandardCharsets . UTF_8 ));
1509
+ bb .writeBytes (routingKey .getBytes (CHARSET ));
1440
1510
bb .writeShort (superStream .length ());
1441
- bb .writeBytes (superStream .getBytes (StandardCharsets . UTF_8 ));
1511
+ bb .writeBytes (superStream .getBytes (CHARSET ));
1442
1512
OutstandingRequest <List <String >> request = outstandingRequest ();
1443
1513
outstandingRequests .put (correlationId , request );
1444
1514
channel .writeAndFlush (bb );
@@ -1471,7 +1541,7 @@ public List<String> partitions(String superStream) {
1471
1541
bb .writeShort (VERSION_1 );
1472
1542
bb .writeInt (correlationId );
1473
1543
bb .writeShort (superStream .length ());
1474
- bb .writeBytes (superStream .getBytes (StandardCharsets . UTF_8 ));
1544
+ bb .writeBytes (superStream .getBytes (CHARSET ));
1475
1545
OutstandingRequest <List <String >> request = outstandingRequest ();
1476
1546
outstandingRequests .put (correlationId , request );
1477
1547
channel .writeAndFlush (bb );
@@ -1532,7 +1602,7 @@ StreamStatsResponse streamStats(String stream) {
1532
1602
bb .writeShort (VERSION_1 );
1533
1603
bb .writeInt (correlationId );
1534
1604
bb .writeShort (stream .length ());
1535
- bb .writeBytes (stream .getBytes (StandardCharsets . UTF_8 ));
1605
+ bb .writeBytes (stream .getBytes (CHARSET ));
1536
1606
OutstandingRequest <StreamStatsResponse > request = outstandingRequest ();
1537
1607
outstandingRequests .put (correlationId , request );
1538
1608
channel .writeAndFlush (bb );
0 commit comments