/**
* $Id: MessageDecoder.java 1831 2013-05-16 01:39:51Z shijia.wxr $
*/
package com.alibaba.rocketmq.common;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.rocketmq.common.sysflag.MessageSysFlag;
/**
* ��Ϣ����
*
* @author vintage.wang@gmail.com shijia.wxr@taobao.com
*/
public class MessageDecoder {
/**
* ��ϢID����
*/
public final static int MSG_ID_LENGTH = 4 + 8 + 8;
/**
* �洢��¼�����ֶ�λ��
*/
public final static int MessageMagicCodePostion = 4;
public final static int MessageFlagPostion = 16;
public final static int MessagePhysicOffsetPostion = 28;
public final static int MessageStoreTimestampPostion = 56;
public static String createMessageId(final ByteBuffer input, final int time, final ByteBuffer addr,
final long offset) {
input.flip();
input.limit(MessageDecoder.MSG_ID_LENGTH);
// ��Ϣ�洢ʱ�� 4
input.putInt(time);
// ��Ϣ�洢������ַ IP PORT 8
input.put(addr);
// ��Ϣ��Ӧ��������� OFFSET 8
input.putLong(offset);
return UtilALl.bytes2string(input.array());
}
public static MessageId decodeMessageId(final String msgId) throws UnknownHostException {
long timestamp;
SocketAddress address;
long offset;
// ʱ��
byte[] data = UtilALl.string2bytes(msgId.substring(0, 8));
ByteBuffer bb = ByteBuffer.wrap(data);
timestamp = bb.getInt(0) * 1000;
// ��ַ
byte[] ip = UtilALl.string2bytes(msgId.substring(8, 16));
byte[] port = UtilALl.string2bytes(msgId.substring(16, 24));
bb = ByteBuffer.wrap(port);
int portInt = bb.getInt(0);
address = new InetSocketAddress(InetAddress.getByAddress(ip), portInt);
// offset
data = UtilALl.string2bytes(msgId.substring(24, 40));
bb = ByteBuffer.wrap(data);
offset = bb.getLong(0);
return new MessageId(timestamp, address, offset);
}
public static MessageExt decode(java.nio.ByteBuffer byteBuffer) {
return decode(byteBuffer, true);
}
/**
* �ͻ���ʹ�ã�SLAVEҲ��ʹ��
*/
public static MessageExt decode(java.nio.ByteBuffer byteBuffer, final boolean readBody) {
try {
MessageExt msgExt = new MessageExt();
// 1 TOTALSIZE
int storeSize = byteBuffer.getInt();
msgExt.setStoreSize(storeSize);
// 2 MAGICCODE
byteBuffer.getInt();
// 3 BODYCRC
int bodyCRC = byteBuffer.getInt();
msgExt.setBodyCRC(bodyCRC);
// 4 QUEUEID
int queueId = byteBuffer.getInt();
msgExt.setQueueId(queueId);
// 5 FLAG
int flag = byteBuffer.getInt();
msgExt.setFlag(flag);
// 6 QUEUEOFFSET
long queueOffset = byteBuffer.getLong();
msgExt.setQueueOffset(queueOffset);
// 7 PHYSICALOFFSET
long physicOffset = byteBuffer.getLong();
msgExt.setCommitLogOffset(physicOffset);
// 8 SYSFLAG
int sysFlag = byteBuffer.getInt();
msgExt.setSysFlag(sysFlag);
// 9 BORNTIMESTAMP
long bornTimeStamp = byteBuffer.getLong();
msgExt.setBornTimestamp(bornTimeStamp);
// 10 BORNHOST
byte[] bornHost = new byte[4];
byteBuffer.get(bornHost, 0, 4);
int port = byteBuffer.getInt();
msgExt.setBornHost(new InetSocketAddress(InetAddress.getByAddress(bornHost), port));
// 11 STORETIMESTAMP
long storeTimestamp = byteBuffer.getLong();
msgExt.setStoreTimestamp(storeTimestamp);
// 12 STOREHOST
byte[] storeHost = new byte[4];
byteBuffer.get(storeHost, 0, 4);
port = byteBuffer.getInt();
msgExt.setStoreHost(new InetSocketAddress(InetAddress.getByAddress(storeHost), port));
// 13 RECONSUMETIMES
int reconsumeTimes = byteBuffer.getInt();
msgExt.setReconsumeTimes(reconsumeTimes);
// 14 Prepared Transaction Offset
long preparedTransactionOffset = byteBuffer.getLong();
msgExt.setPreparedTransactionOffset(preparedTransactionOffset);
// 15 BODY
int bodyLen = byteBuffer.getInt();
if (bodyLen > 0) {
if (readBody) {
byte[] body = new byte[bodyLen];
byteBuffer.get(body);
// uncompress body
if ((sysFlag & MessageSysFlag.CompressedFlag) == MessageSysFlag.CompressedFlag) {
body = UtilALl.uncompress(body);
}
msgExt.setBody(body);
}
else {
byteBuffer.position(byteBuffer.position() + bodyLen);
}
}
// 16 TOPIC
byte topicLen = byteBuffer.get();
byte[] topic = new byte[(int) topicLen];
byteBuffer.get(topic);
msgExt.setTopic(new String(topic));
// 17 properties
short propertiesLength = byteBuffer.getShort();
if (propertiesLength > 0) {
byte[] properties = new byte[propertiesLength];
byteBuffer.get(properties);
String propertiesString = new String(properties);
Map<String, String> map = string2messageProperties(propertiesString);
msgExt.setProperties(map);
}
// ��ϢID
ByteBuffer byteBufferMsgId = ByteBuffer.allocate(MSG_ID_LENGTH);
String msgId =
createMessageId(byteBufferMsgId, (int) (msgExt.getStoreTimestamp() / 1000),
msgExt.getStoreHostBytes(), msgExt.getCommitLogOffset());
msgExt.setMsgId(msgId);
return msgExt;
}
catch (UnknownHostException e) {
byteBuffer.position(byteBuffer.limit());
}
catch (BufferUnderflowException e) {
byteBuffer.position(byteBuffer.limit());
}
catch (Exception e) {
byteBuffer.position(byteBuffer.limit());
}
return null;
}
public static List<MessageExt> decodes(java.nio.ByteBuffer byteBuffer) {
return decodes(byteBuffer, true);
}
/**
* �ͻ���ʹ��
*/
public static List<MessageExt> decodes(java.nio.ByteBuffer byteBuffer, final boolean readBody) {
List<MessageExt> msgExts = new ArrayList<MessageExt>();
while (byteBuffer.hasRemaining()) {
MessageExt msgExt = decode(byteBuffer, readBody);
if (null != msgExt) {
msgExts.add(msgExt);
}
else {
log.warn("message decode error.");
break;
}
}
return msgExts;
}
/**
* ���л���Ϣ����
*/
public static final char NAME_VALUE_SEPARATOR = 1;
public static final char PROPERTY_SEPARATOR = 2;
public static String messageProperties2String(Map<String, String> properties) {
StringBuilder sb = new StringBuilder();
if (properties != null) {
for (final Map.Entry<String, String> entry : properties.entrySet()) {
final String name = entry.getKey();
final String value = entry.getValue();
sb.append(name);
sb.append(NAME_VALUE_SEPARATOR);
sb.append(value);
sb.append(PROPERTY_SEPARATOR);
}
}
return sb.toString();
}
public static Map<String, String> string2messageProperties(final String properties) {
Map<String, String> map = new HashMap<String, String>();
if (properties != null) {
String[] items = properties.split(String.valueOf(PROPERTY_SEPARATOR));
if (items != null) {
for (String i : items) {
String[] nv = i.split(String.valueOf(NAME_VALUE_SEPARATOR));
if (nv != null && 2 == nv.length) {
map.put(nv[0], nv[1]);
}
}
}
}
return map;
}
private static final Logger log = LoggerFactory.getLogger(MixAll.CommonLoggerName);
}