All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rabbitmq.client.impl.AMQCommand Maven / Gradle / Ivy

Go to download

The RabbitMQ Java client library allows Java applications to interface with RabbitMQ.

There is a newer version: 5.22.0
Show newest version
// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
//
// This software, the RabbitMQ Java client library, is triple-licensed under the
// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2.  For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].

package com.rabbitmq.client.impl;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Command;

/**
 * AMQP 0-9-1-specific implementation of {@link Command} which accumulates
 * method, header and body from a series of frames, unless these are
 * supplied at construction time.
 * 

Concurrency

* This class is thread-safe. */ public class AMQCommand implements Command { /** EMPTY_FRAME_SIZE = 8 = 1 + 2 + 4 + 1 *
  • 1 byte of frame type
  • *
  • 2 bytes of channel number
  • *
  • 4 bytes of frame payload length
  • *
  • 1 byte of payload trailer FRAME_END byte
* See {@link #checkEmptyFrameSize}, an assertion checked at * startup. */ public static final int EMPTY_FRAME_SIZE = 8; /** The assembler for this command - synchronised on - contains all the state */ private final CommandAssembler assembler; private final Lock assemblerLock = new ReentrantLock(); AMQCommand(int maxBodyLength) { this(null, null, null, maxBodyLength); } /** Construct a command ready to fill in by reading frames */ public AMQCommand() { this(null, null, null, Integer.MAX_VALUE); } /** * Construct a command with just a method, and without header or body. * @param method the wrapped method */ public AMQCommand(com.rabbitmq.client.Method method) { this(method, null, null, Integer.MAX_VALUE); } /** * Construct a command with a specified method, header and body. * @param method the wrapped method * @param contentHeader the wrapped content header * @param body the message body data */ public AMQCommand(com.rabbitmq.client.Method method, AMQContentHeader contentHeader, byte[] body) { this.assembler = new CommandAssembler((Method) method, contentHeader, body, Integer.MAX_VALUE); } /** * Construct a command with a specified method, header and body. * @param method the wrapped method * @param contentHeader the wrapped content header * @param body the message body data * @param maxBodyLength the maximum size for an inbound message body */ public AMQCommand(com.rabbitmq.client.Method method, AMQContentHeader contentHeader, byte[] body, int maxBodyLength) { this.assembler = new CommandAssembler((Method) method, contentHeader, body, maxBodyLength); } /** Public API - {@inheritDoc} */ @Override public Method getMethod() { return this.assembler.getMethod(); } /** Public API - {@inheritDoc} */ @Override public AMQContentHeader getContentHeader() { return this.assembler.getContentHeader(); } /** Public API - {@inheritDoc} */ @Override public byte[] getContentBody() { return this.assembler.getContentBody(); } public boolean handleFrame(Frame f) throws IOException { return this.assembler.handleFrame(f); } /** * Sends this command down the named channel on the channel's * connection, possibly in multiple frames. * @param channel the channel on which to transmit the command * @throws IOException if an error is encountered */ public void transmit(AMQChannel channel) throws IOException { int channelNumber = channel.getChannelNumber(); AMQConnection connection = channel.getConnection(); assemblerLock.lock(); try { Method m = this.assembler.getMethod(); if (m.hasContent()) { byte[] body = this.assembler.getContentBody(); Frame headerFrame = this.assembler.getContentHeader().toFrame(channelNumber, body.length); int frameMax = connection.getFrameMax(); boolean cappedFrameMax = frameMax > 0; int bodyPayloadMax = cappedFrameMax ? frameMax - EMPTY_FRAME_SIZE : body.length; if (cappedFrameMax && headerFrame.size() > frameMax) { String msg = String.format("Content headers exceeded max frame size: %d > %d", headerFrame.size(), frameMax); throw new IllegalArgumentException(msg); } connection.writeFrame(m.toFrame(channelNumber)); connection.writeFrame(headerFrame); for (int offset = 0; offset < body.length; offset += bodyPayloadMax) { int remaining = body.length - offset; int fragmentLength = (remaining < bodyPayloadMax) ? remaining : bodyPayloadMax; Frame frame = Frame.fromBodyFragment(channelNumber, body, offset, fragmentLength); connection.writeFrame(frame); } } else { connection.writeFrame(m.toFrame(channelNumber)); } } finally { assemblerLock.unlock(); } connection.flush(); } @Override public String toString() { return toString(false); } public String toString(boolean suppressBody){ assemblerLock.lock(); try { return new StringBuilder() .append('{') .append(this.assembler.getMethod()) .append(", ") .append(this.assembler.getContentHeader()) .append(", ") .append(contentBodyStringBuilder( this.assembler.getContentBody(), suppressBody)) .append('}').toString(); } finally { assemblerLock.unlock(); } } private static StringBuilder contentBodyStringBuilder(byte[] body, boolean suppressBody) { try { if (suppressBody) { return new StringBuilder().append(body.length).append(" bytes of payload"); } else { return new StringBuilder().append('\"').append(new String(body, "UTF-8")).append('\"'); } } catch (Exception e) { return new StringBuilder().append('|').append(body.length).append('|'); } } /** Called to check internal code assumptions. */ public static void checkPreconditions() { checkEmptyFrameSize(); } /** * Since we're using a pre-computed value for EMPTY_FRAME_SIZE we * check this is actually correct when run against the framing * code in Frame. */ private static void checkEmptyFrameSize() { Frame f = new Frame(AMQP.FRAME_BODY, 0, new byte[0]); ByteArrayOutputStream s = new ByteArrayOutputStream(); try { f.writeTo(new DataOutputStream(s)); } catch (IOException ioe) { throw new IllegalStateException("IOException while checking EMPTY_FRAME_SIZE"); } int actualLength = s.toByteArray().length; if (EMPTY_FRAME_SIZE != actualLength) { throw new IllegalStateException("Internal error: expected EMPTY_FRAME_SIZE(" + EMPTY_FRAME_SIZE + ") is not equal to computed value: " + actualLength); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy