1818import java .io .ByteArrayOutputStream ;
1919import java .io .DataOutputStream ;
2020import java .io .IOException ;
21+ import java .nio .ByteBuffer ;
2122import java .util .concurrent .locks .Lock ;
2223import java .util .concurrent .locks .ReentrantLock ;
2324
2425import com .rabbitmq .client .AMQP ;
2526import com .rabbitmq .client .Command ;
27+ import com .rabbitmq .client .WriteListener ;
2628
2729/**
2830 * AMQP 0-9-1-specific implementation of {@link Command} which accumulates
@@ -46,44 +48,49 @@ public class AMQCommand implements Command {
4648 /** The assembler for this command - synchronised on - contains all the state */
4749 private final CommandAssembler assembler ;
4850 private final Lock assemblerLock = new ReentrantLock ();
51+ private final WriteListener writeListener ;
4952
53+ /** Construct a command for inbound frame assembly with a max body length. */
5054 AMQCommand (int maxBodyLength ) {
51- this (null , null , null , maxBodyLength );
55+ this .assembler = new CommandAssembler (null , null , maxBodyLength );
56+ this .writeListener = null ;
5257 }
5358
54- /** Construct a command ready to fill in by reading frames */
59+ /** Construct a command ready to fill in by reading frames. */
5560 public AMQCommand () {
56- this (null , null , null , Integer .MAX_VALUE );
61+ this (Integer .MAX_VALUE );
5762 }
5863
5964 /**
6065 * Construct a command with just a method, and without header or body.
6166 * @param method the wrapped method
6267 */
6368 public AMQCommand (com .rabbitmq .client .Method method ) {
64- this (method , null , null , Integer .MAX_VALUE );
69+ this .assembler = new CommandAssembler ((Method ) method , null , Integer .MAX_VALUE );
70+ this .writeListener = null ;
6571 }
6672
6773 /**
68- * Construct a command with a specified method, header and body .
74+ * Construct a command with a ByteBuffer body for transmission .
6975 * @param method the wrapped method
7076 * @param contentHeader the wrapped content header
71- * @param body the message body data
77+ * @param body the message body as a ByteBuffer
7278 */
73- public AMQCommand (com .rabbitmq .client .Method method , AMQContentHeader contentHeader , byte [] body ) {
74- this . assembler = new CommandAssembler (( Method ) method , contentHeader , body , Integer . MAX_VALUE );
79+ public AMQCommand (com .rabbitmq .client .Method method , AMQContentHeader contentHeader , ByteBuffer body ) {
80+ this ( method , contentHeader , body , null );
7581 }
7682
7783 /**
78- * Construct a command with a specified method, header and body .
84+ * Construct a command with a ByteBuffer body and a write completion listener .
7985 * @param method the wrapped method
8086 * @param contentHeader the wrapped content header
81- * @param body the message body data
82- * @param maxBodyLength the maximum size for an inbound message body
87+ * @param body the message body as a ByteBuffer
88+ * @param writeListener called when the network layer finishes writing, may be {@code null}
8389 */
84- public AMQCommand (com .rabbitmq .client .Method method , AMQContentHeader contentHeader , byte [] body ,
85- int maxBodyLength ) {
86- this .assembler = new CommandAssembler ((Method ) method , contentHeader , body , maxBodyLength );
90+ public AMQCommand (com .rabbitmq .client .Method method , AMQContentHeader contentHeader , ByteBuffer body ,
91+ WriteListener writeListener ) {
92+ this .assembler = new CommandAssembler ((Method ) method , contentHeader , body );
93+ this .writeListener = writeListener ;
8794 }
8895
8996 /** Public API - {@inheritDoc} */
@@ -122,13 +129,13 @@ public void transmit(AMQChannel channel) throws IOException {
122129 try {
123130 Method m = this .assembler .getMethod ();
124131 if (m .hasContent ()) {
125- byte [] body = this .assembler .getContentBody ();
126-
127- Frame headerFrame = this .assembler .getContentHeader ().toFrame (channelNumber , body . length );
132+ ByteBuffer body = this .assembler .getByteBufferBody ();
133+ int bodySize = body == null ? 0 : body . remaining ();
134+ Frame headerFrame = this .assembler .getContentHeader ().toFrame (channelNumber , bodySize );
128135
129136 int frameMax = connection .getFrameMax ();
130137 boolean cappedFrameMax = frameMax > 0 ;
131- int bodyPayloadMax = cappedFrameMax ? frameMax - EMPTY_FRAME_SIZE : body . length ;
138+ int bodyPayloadMax = cappedFrameMax ? frameMax - EMPTY_FRAME_SIZE : bodySize ;
132139
133140 if (cappedFrameMax && headerFrame .size () > frameMax ) {
134141 String msg = String .format ("Content headers exceeded max frame size: %d > %d" , headerFrame .size (), frameMax );
@@ -137,14 +144,14 @@ public void transmit(AMQChannel channel) throws IOException {
137144 connection .writeFrame (m .toFrame (channelNumber ));
138145 connection .writeFrame (headerFrame );
139146
140- for ( int offset = 0 ; offset < body . length ; offset += bodyPayloadMax ) {
141- int remaining = body .length - offset ;
142-
143- int fragmentLength = ( remaining < bodyPayloadMax ) ? remaining
144- : bodyPayloadMax ;
145- Frame frame = Frame .fromBodyFragment (channelNumber , body ,
146- offset , fragmentLength );
147- connection . writeFrame ( frame );
147+ if ( body != null ) {
148+ int bodyPosition = body .position () ;
149+ for ( int offset = 0 ; offset < bodySize ; offset += bodyPayloadMax ) {
150+ int remaining = bodySize - offset ;
151+ int fragmentLength = ( remaining < bodyPayloadMax ) ? remaining : bodyPayloadMax ;
152+ Frame frame = Frame .fromBodyFragment (channelNumber , body , bodyPosition + offset , fragmentLength );
153+ connection . writeFrame ( frame );
154+ }
148155 }
149156 } else {
150157 connection .writeFrame (m .toFrame (channelNumber ));
@@ -153,7 +160,7 @@ public void transmit(AMQChannel channel) throws IOException {
153160 assemblerLock .unlock ();
154161 }
155162
156- connection .flush ();
163+ connection .flush (this . writeListener );
157164 }
158165
159166 @ Override public String toString () {
@@ -200,7 +207,7 @@ public static void checkPreconditions() {
200207 * code in Frame.
201208 */
202209 private static void checkEmptyFrameSize () {
203- Frame f = new Frame (AMQP .FRAME_BODY , 0 , new byte [0 ]);
210+ Frame f = new Frame (AMQP .FRAME_BODY , 0 , ByteBuffer . wrap ( new byte [0 ]) );
204211 ByteArrayOutputStream s = new ByteArrayOutputStream ();
205212 try {
206213 f .writeTo (new DataOutputStream (s ));
0 commit comments