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

org.apache.qpid.codec.AMQDecoder Maven / Gradle / Ivy

There is a newer version: 6.1.7
Show newest version
/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */
package org.apache.qpid.codec;

import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import org.apache.qpid.framing.*;
import org.apache.qpid.protocol.AMQConstant;

/**
 * AMQDecoder delegates the decoding of AMQP either to a data block decoder, or in the case of new connections, to a
 * protocol initiation decoder. It is a cumulative decoder, which means that it can accumulate data to decode in the
 * buffer until there is enough data to decode.
 *
 * 

One instance of this class is created per session, so any changes or configuration done at run time to the * decoder will only affect decoding of the protocol session data to which is it bound. * *

* TODO If protocol initiation decoder not needed, then don't create it. Probably not a big deal, but it adds to the * per-session overhead. */ public abstract class AMQDecoder { private static final int MAX_BUFFERS_LIMIT = 10; private final T _methodProcessor; /** Holds the protocol initiation decoder. */ private ProtocolInitiation.Decoder _piDecoder = new ProtocolInitiation.Decoder(); /** Flag to indicate whether this decoder needs to handle protocol initiation. */ private boolean _expectProtocolInitiation; private boolean _firstRead = true; private int _maxFrameSize = AMQConstant.FRAME_MIN_SIZE.getCode(); /** * Creates a new AMQP decoder. * @param expectProtocolInitiation true if this decoder needs to handle protocol initiation. * @param methodProcessor method processor */ protected AMQDecoder(boolean expectProtocolInitiation, T methodProcessor) { _expectProtocolInitiation = expectProtocolInitiation; _methodProcessor = methodProcessor; } /** * Sets the protocol initation flag, that determines whether decoding is handled by the data decoder of the protocol * initation decoder. This method is expected to be called with false once protocol initation completes. * * @param expectProtocolInitiation true to use the protocol initiation decoder, false to use the * data decoder. */ public void setExpectProtocolInitiation(boolean expectProtocolInitiation) { _expectProtocolInitiation = expectProtocolInitiation; } public void setMaxFrameSize(final int frameMax) { _maxFrameSize = frameMax; } public T getMethodProcessor() { return _methodProcessor; } protected void decode(final MarkableDataInput msg) throws IOException, AMQFrameDecodingException { // If this is the first read then we may be getting a protocol initiation back if we tried to negotiate // an unsupported version if(_firstRead && msg.available()>0) { msg.mark(1); _firstRead = false; if(!_expectProtocolInitiation && (((int)msg.readByte()) &0xff) > 8) { _expectProtocolInitiation = true; } msg.reset(); } boolean enoughData = true; while (enoughData) { if(!_expectProtocolInitiation) { enoughData = decodable(msg); if (enoughData) { processInput(msg); } } else { enoughData = _piDecoder.decodable(msg); if (enoughData) { _methodProcessor.receiveProtocolHeader(new ProtocolInitiation(msg)); } } } } private boolean decodable(final MarkableDataInput in) throws AMQFrameDecodingException, IOException { final int remainingAfterAttributes = in.available() - (1 + 2 + 4 + 1); // type, channel, body length and end byte if (remainingAfterAttributes < 0) { return false; } in.mark(8); in.skip(1 + 2); // Get an unsigned int, lifted from MINA ByteBuffer getUnsignedInt() final long bodySize = in.readInt() & 0xffffffffL; if (bodySize > _maxFrameSize) { throw new AMQFrameDecodingException(AMQConstant.FRAME_ERROR, "Incoming frame size of " + bodySize + " is larger than negotiated maximum of " + _maxFrameSize); } in.reset(); return (remainingAfterAttributes >= bodySize); } private void processInput(final MarkableDataInput in) throws AMQFrameDecodingException, AMQProtocolVersionException, IOException { final byte type = in.readByte(); final int channel = in.readUnsignedShort(); final long bodySize = EncodingUtils.readUnsignedInteger(in); // bodySize can be zero if ((channel < 0) || (bodySize < 0)) { throw new AMQFrameDecodingException(AMQConstant.FRAME_ERROR, "Undecodable frame: type = " + type + " channel = " + channel + " bodySize = " + bodySize); } processFrame(channel, type, bodySize, in); byte marker = in.readByte(); if ((marker & 0xFF) != 0xCE) { throw new AMQFrameDecodingException(AMQConstant.FRAME_ERROR, "End of frame marker not found. Read " + marker + " length=" + bodySize + " type=" + type); } } protected void processFrame(final int channel, final byte type, final long bodySize, final MarkableDataInput in) throws AMQFrameDecodingException, IOException { switch (type) { case 1: processMethod(channel, in); break; case 2: ContentHeaderBody.process(in, _methodProcessor.getChannelMethodProcessor(channel), bodySize); break; case 3: ContentBody.process(in, _methodProcessor.getChannelMethodProcessor(channel), bodySize); break; case 8: HeartbeatBody.process(channel, in, _methodProcessor, bodySize); break; default: throw new AMQFrameDecodingException(AMQConstant.FRAME_ERROR, "Unsupported frame type: " + type); } } abstract void processMethod(int channelId, MarkableDataInput in) throws AMQFrameDecodingException, IOException; AMQFrameDecodingException newUnknownMethodException(final int classId, final int methodId, ProtocolVersion protocolVersion) { return new AMQFrameDecodingException(AMQConstant.COMMAND_INVALID, "Method " + methodId + " unknown in AMQP version " + protocolVersion + " (while trying to decode class " + classId + " method " + methodId + "."); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy