de.htwk_leipzig.bis.connection.handshake.clientRewrite.AMQCommand.java Source code

Java tutorial

Introduction

Here is the source code for de.htwk_leipzig.bis.connection.handshake.clientRewrite.AMQCommand.java

Source

//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License
//at http://www.mozilla.org/MPL/
//
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
//the License for the specific language governing rights and
//limitations under the License.
//
//The Original Code is RabbitMQ.
//
//The Initial Developer of the Original Code is GoPivotal, Inc.
//Copyright (c) 2007-2014 GoPivotal, Inc.  All rights reserved.
//
package de.htwk_leipzig.bis.connection.handshake.clientRewrite;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Command;
import com.rabbitmq.client.impl.AMQContentHeader;
import com.rabbitmq.client.impl.Frame;
import com.rabbitmq.client.impl.Method;

/**
 * AMQ-specific implementation of {@link Command} which accumulates method,
 * header and body from a series of frames, unless these are supplied at
 * construction time.
 * <p/>
 * <b>Concurrency</b><br/>
 * This class is thread-safe.
 */
public class AMQCommand implements Command {

    /**
     * EMPTY_FRAME_SIZE = 8 = 1 + 2 + 4 + 1
     * <ul>
     * <li>1 byte of frame type</li>
     * <li>2 bytes of channel number</li>
     * <li>4 bytes of frame payload length</li>
     * <li>1 byte of payload trailer FRAME_END byte</li>
     * </ul>
     * 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;

    /** Construct a command ready to fill in by reading frames */
    public AMQCommand() {
        this(null, null, null);
    }

    /**
     * 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);
    }

    /**
     * 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);
    }

    /** Public API - {@inheritDoc} */
    public Method getMethod() {
        return this.assembler.getMethod();
    }

    /** Public API - {@inheritDoc} */
    public AMQContentHeader getContentHeader() {
        return this.assembler.getContentHeader();
    }

    /** Public API - {@inheritDoc} */
    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();

        synchronized (assembler) {
            Method m = this.assembler.getMethod();
            connection.writeFrame(m.toFrame(channelNumber));
            if (m.hasContent()) {
                byte[] body = this.assembler.getContentBody();

                connection.writeFrame(this.assembler.getContentHeader().toFrame(channelNumber, body.length));

                int frameMax = connection.getFrameMax();
                int bodyPayloadMax = (frameMax == 0) ? body.length : frameMax - EMPTY_FRAME_SIZE;

                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);
                }
            }
        }

        connection.flush();
    }

    @Override
    public String toString() {
        return toString(false);
    }

    public String toString(boolean suppressBody) {
        synchronized (assembler) {
            return new StringBuilder().append('{').append(this.assembler.getMethod()).append(", ")
                    .append(this.assembler.getContentHeader()).append(", ")
                    .append(contentBodyStringBuilder(this.assembler.getContentBody(), suppressBody)).append('}')
                    .toString();
        }
    }

    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 AssertionError("IOException while checking EMPTY_FRAME_SIZE");
        }
        int actualLength = s.toByteArray().length;
        if (EMPTY_FRAME_SIZE != actualLength) {
            throw new AssertionError("Internal error: expected EMPTY_FRAME_SIZE(" + EMPTY_FRAME_SIZE
                    + ") is not equal to computed value: " + actualLength);
        }
    }
}