/*
* 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.activemq.artemis.core.protocol.core.impl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.buffers.impl.ChannelBufferWrapper;
import org.apache.activemq.artemis.core.protocol.core.Packet;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.utils.DataConstants;
public class PacketImpl implements Packet {
// Constants -------------------------------------------------------------------------
public static final int ADDRESSING_CHANGE_VERSION = 129;
public static final SimpleString OLD_QUEUE_PREFIX = new SimpleString("jms.queue.");
public static final SimpleString OLD_TOPIC_PREFIX = new SimpleString("jms.topic.");
// The minimal size for all the packets, Common data for all the packets (look at
// PacketImpl.encode)
public static final int PACKET_HEADERS_SIZE = DataConstants.SIZE_INT + DataConstants.SIZE_BYTE +
DataConstants.SIZE_LONG;
protected long channelID;
private final byte type;
protected int size = -1;
// The packet types
// -----------------------------------------------------------------------------------
public static final byte PING = 10;
public static final byte DISCONNECT = 11;
public static final byte DISCONNECT_CONSUMER = 12;
public static final byte DISCONNECT_CONSUMER_KILL = 13;
// Miscellaneous
public static final byte EXCEPTION = 20;
public static final byte NULL_RESPONSE = 21;
public static final byte PACKETS_CONFIRMED = 22;
// Server
public static final byte CREATESESSION = 30;
public static final byte CREATESESSION_RESP = 31;
public static final byte REATTACH_SESSION = 32;
public static final byte REATTACH_SESSION_RESP = 33;
public static final byte CREATE_QUEUE = 34;
public static final byte DELETE_QUEUE = 35;
public static final byte CREATE_SHARED_QUEUE = 36;
// Session
public static final byte SESS_XA_FAILED = 39;
public static final byte SESS_CREATECONSUMER = 40;
public static final byte SESS_ACKNOWLEDGE = 41;
public static final byte SESS_EXPIRED = 42;
public static final byte SESS_COMMIT = 43;
public static final byte SESS_ROLLBACK = 44;
public static final byte SESS_QUEUEQUERY = 45;
public static final byte SESS_QUEUEQUERY_RESP = 46;
public static final byte SESS_BINDINGQUERY = 49;
public static final byte SESS_BINDINGQUERY_RESP = 50;
public static final byte SESS_XA_START = 51;
public static final byte SESS_XA_END = 52;
public static final byte SESS_XA_COMMIT = 53;
public static final byte SESS_XA_PREPARE = 54;
public static final byte SESS_XA_RESP = 55;
public static final byte SESS_XA_ROLLBACK = 56;
public static final byte SESS_XA_JOIN = 57;
public static final byte SESS_XA_SUSPEND = 58;
public static final byte SESS_XA_RESUME = 59;
public static final byte SESS_XA_FORGET = 60;
public static final byte SESS_XA_INDOUBT_XIDS = 61;
public static final byte SESS_XA_INDOUBT_XIDS_RESP = 62;
public static final byte SESS_XA_SET_TIMEOUT = 63;
public static final byte SESS_XA_SET_TIMEOUT_RESP = 64;
public static final byte SESS_XA_GET_TIMEOUT = 65;
public static final byte SESS_XA_GET_TIMEOUT_RESP = 66;
public static final byte SESS_START = 67;
public static final byte SESS_STOP = 68;
public static final byte SESS_CLOSE = 69;
public static final byte SESS_FLOWTOKEN = 70;
public static final byte SESS_SEND = 71;
public static final byte SESS_SEND_LARGE = 72;
public static final byte SESS_SEND_CONTINUATION = 73;
public static final byte SESS_CONSUMER_CLOSE = 74;
public static final byte SESS_RECEIVE_MSG = 75;
public static final byte SESS_RECEIVE_LARGE_MSG = 76;
public static final byte SESS_RECEIVE_CONTINUATION = 77;
public static final byte SESS_FORCE_CONSUMER_DELIVERY = 78;
public static final byte SESS_PRODUCER_REQUEST_CREDITS = 79;
public static final byte SESS_PRODUCER_CREDITS = 80;
public static final byte SESS_INDIVIDUAL_ACKNOWLEDGE = 81;
public static final byte SESS_PRODUCER_FAIL_CREDITS = 82;
// Replication
public static final byte REPLICATION_RESPONSE = 90;
public static final byte REPLICATION_APPEND = 91;
public static final byte REPLICATION_APPEND_TX = 92;
public static final byte REPLICATION_DELETE = 93;
public static final byte REPLICATION_DELETE_TX = 94;
public static final byte REPLICATION_PREPARE = 95;
public static final byte REPLICATION_COMMIT_ROLLBACK = 96;
public static final byte REPLICATION_PAGE_WRITE = 97;
public static final byte REPLICATION_PAGE_EVENT = 98;
public static final byte REPLICATION_LARGE_MESSAGE_BEGIN = 99;
public static final byte REPLICATION_LARGE_MESSAGE_END = 100;
public static final byte REPLICATION_LARGE_MESSAGE_WRITE = 101;
/*
* code 102 was REPLICATION_COMPARE_DATA, released into production as a message, but as part of
* the (then) non-function replication system.
*/
public static final byte REPLICATION_SYNC_FILE = 103;
public static final byte SESS_ADD_METADATA = 104;
public static final byte SESS_ADD_METADATA2 = 105;
public static final byte SESS_UNIQUE_ADD_METADATA = 106;
// HA
public static final byte CLUSTER_TOPOLOGY = 110;
public static final byte NODE_ANNOUNCE = 111;
public static final byte SUBSCRIBE_TOPOLOGY = 112;
// For newer versions
public static final byte SUBSCRIBE_TOPOLOGY_V2 = 113;
public static final byte CLUSTER_TOPOLOGY_V2 = 114;
public static final byte BACKUP_REGISTRATION = 115;
public static final byte BACKUP_REGISTRATION_FAILED = 116;
public static final byte REPLICATION_START_FINISH_SYNC = 120;
public static final byte REPLICATION_SCHEDULED_FAILOVER = 121;
public static final byte CLUSTER_TOPOLOGY_V3 = 122;
//do not reuse
//public static final byte NODE_ANNOUNCE_V2 = 123;
public static final byte DISCONNECT_V2 = 124;
public static final byte CLUSTER_CONNECT = 125;
public static final byte CLUSTER_CONNECT_REPLY = 126;
public static final byte BACKUP_REQUEST = 127;
//oops ran out of positive bytes
public static final byte BACKUP_REQUEST_RESPONSE = -1;
public static final byte QUORUM_VOTE = -2;
public static final byte QUORUM_VOTE_REPLY = -3;
public static final byte CHECK_FOR_FAILOVER = -4;
public static final byte CHECK_FOR_FAILOVER_REPLY = -5;
public static final byte SCALEDOWN_ANNOUNCEMENT = -6;
public static final byte SESS_QUEUEQUERY_RESP_V2 = -7;
public static final byte SESS_BINDINGQUERY_RESP_V2 = -8;
public static final byte REPLICATION_RESPONSE_V2 = -9;
public static final byte SESS_BINDINGQUERY_RESP_V3 = -10;
public static final byte CREATE_ADDRESS = -11;
public static final byte CREATE_QUEUE_V2 = -12;
public static final byte CREATE_SHARED_QUEUE_V2 = -13;
public static final byte SESS_QUEUEQUERY_RESP_V3 = -14;
public static final byte SESS_BINDINGQUERY_RESP_V4 = -15;
// Static --------------------------------------------------------
public PacketImpl(final byte type) {
this.type = type;
}
// Public --------------------------------------------------------
public SimpleString convertName(SimpleString name) {
if (name == null) {
return null;
}
if (name.startsWith(OLD_QUEUE_PREFIX)) {
return name.subSeq(OLD_QUEUE_PREFIX.length(), name.length());
} else if (name.startsWith(OLD_TOPIC_PREFIX)) {
return name.subSeq(OLD_TOPIC_PREFIX.length(), name.length());
} else {
return name;
}
}
@Override
public byte getType() {
return type;
}
@Override
public long getChannelID() {
return channelID;
}
@Override
public void setChannelID(final long channelID) {
this.channelID = channelID;
}
@Override
public ActiveMQBuffer encode(final RemotingConnection connection) {
ActiveMQBuffer buffer = createPacket(connection);
// The standard header fields
buffer.writeInt(0); // The length gets filled in at the end
buffer.writeByte(type);
buffer.writeLong(channelID);
encodeRest(buffer);
size = buffer.writerIndex();
// The length doesn't include the actual length byte
int len = size - DataConstants.SIZE_INT;
buffer.setInt(0, len);
return buffer;
}
protected ActiveMQBuffer createPacket(RemotingConnection connection) {
int size = expectedEncodeSize();
if (connection == null) {
return new ChannelBufferWrapper(Unpooled.buffer(size));
} else {
return connection.createTransportBuffer(size);
}
}
@Override
public void decode(final ActiveMQBuffer buffer) {
channelID = buffer.readLong();
decodeRest(buffer);
size = buffer.readerIndex();
}
protected ByteBuf copyMessageBuffer(ByteBuf buffer, int skipBytes) {
ByteBuf newNettyBuffer = Unpooled.buffer(buffer.capacity() - PACKET_HEADERS_SIZE - skipBytes);
int read = buffer.readerIndex();
int writ = buffer.writerIndex();
buffer.readerIndex(PACKET_HEADERS_SIZE);
newNettyBuffer.writeBytes(buffer, buffer.readableBytes() - skipBytes);
buffer.setIndex( read, writ );
newNettyBuffer.setIndex( 0, writ - PACKET_HEADERS_SIZE - skipBytes);
return newNettyBuffer;
}
@Override
public int getPacketSize() {
if (size == -1) {
throw new IllegalStateException("Packet hasn't been encoded/decoded yet");
}
return size;
}
@Override
public boolean isResponse() {
return false;
}
public void encodeRest(final ActiveMQBuffer buffer) {
}
public void decodeRest(final ActiveMQBuffer buffer) {
}
@Override
public boolean isRequiresConfirmations() {
return true;
}
@Override
public String toString() {
return getParentString() + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (channelID ^ (channelID >>> 32));
result = prime * result + size;
result = prime * result + type;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof PacketImpl)) {
return false;
}
PacketImpl other = (PacketImpl) obj;
return (channelID == other.channelID) && (size == other.size) && (type != other.type);
}
protected String getParentString() {
return "PACKET(" + this.getClass().getSimpleName() + ")[type=" + type + ", channelID=" + channelID + ", packetObject=" + this.getClass().getSimpleName();
}
private int stringEncodeSize(final String str) {
return DataConstants.SIZE_INT + str.length() * 2;
}
protected int nullableStringEncodeSize(final String str) {
return DataConstants.SIZE_BOOLEAN + (str != null ? stringEncodeSize(str) : 0);
}
}