/**
* $Id: SendMessageProcessor.java 1831 2013-05-16 01:39:51Z shijia.wxr $
*/
package com.alibaba.rocketmq.broker.processor;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.rocketmq.broker.BrokerController;
import com.alibaba.rocketmq.common.MessageDecoder;
import com.alibaba.rocketmq.common.MixAll;
import com.alibaba.rocketmq.common.TopicConfig;
import com.alibaba.rocketmq.common.TopicFilterType;
import com.alibaba.rocketmq.common.protocol.MQProtos.MQResponseCode;
import com.alibaba.rocketmq.common.protocol.header.SendMessageRequestHeader;
import com.alibaba.rocketmq.common.protocol.header.SendMessageResponseHeader;
import com.alibaba.rocketmq.common.sysflag.MessageSysFlag;
import com.alibaba.rocketmq.remoting.exception.RemotingCommandException;
import com.alibaba.rocketmq.remoting.netty.NettyRequestProcessor;
import com.alibaba.rocketmq.remoting.protocol.RemotingCommand;
import com.alibaba.rocketmq.remoting.protocol.RemotingProtos.ResponseCode;
import com.alibaba.rocketmq.store.MessageExtBrokerInner;
import com.alibaba.rocketmq.store.PutMessageResult;
/**
* ����ͻ��˷�����Ϣ������
*
* @author vintage.wang@gmail.com shijia.wxr@taobao.com
*
*/
public class SendMessageProcessor implements NettyRequestProcessor {
private static final Logger log = LoggerFactory.getLogger(MixAll.BrokerLoggerName);
private final BrokerController brokerController;
private final Random random = new Random(System.currentTimeMillis());
private final SocketAddress storeHost;
public SendMessageProcessor(final BrokerController brokerController) {
this.brokerController = brokerController;
this.storeHost =
new InetSocketAddress(brokerController.getBrokerConfig().getBrokerIP1(), brokerController
.getNettyServerConfig().getListenPort());
}
@Override
public RemotingCommand processRequest(final ChannelHandlerContext ctx, final RemotingCommand request)
throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class);
final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) response.getCustomHeader();
final SendMessageRequestHeader requestHeader =
(SendMessageRequestHeader) request.decodeCommandCustomHeader(SendMessageRequestHeader.class);
// ������ֱ�ӷ��ص��������Ա���Ҫ����
response.setOpaque(request.getOpaque());
if (log.isDebugEnabled()) {
log.debug("receive SendMessage request command, " + request);
}
// ���BrokerȨ��
if (!MixAll.isWriteable(this.brokerController.getBrokerConfig().getBrokerPermission())) {
response.setCode(MQResponseCode.NO_PERMISSION_VALUE);
response.setRemark("the broker[" + this.brokerController.getBrokerConfig().getBrokerIP1()
+ "] sending message is forbidden");
return response;
}
final byte[] body = request.getBody();
// Topic�����Ƿ��뱣���ֶγ�ͻ
if (!this.brokerController.getTopicConfigManager().isTopicCanSendMessage(requestHeader.getTopic())) {
String errorMsg =
"the topic[" + requestHeader.getTopic() + "] is conflict with system reserved words.";
log.warn(errorMsg);
response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
response.setRemark(errorMsg);
return response;
}
// ���topic�Ƿ����
TopicConfig topicConfig =
this.brokerController.getTopicConfigManager().selectTopicConfig(requestHeader.getTopic());
if (null == topicConfig) {
log.error("the topic " + requestHeader.getTopic() + " not exist, producer: "
+ ctx.channel().remoteAddress());
topicConfig =
this.brokerController.getTopicConfigManager().createTopicInSendMessageMethod(
requestHeader.getTopic(), requestHeader.getDefaultTopic(), ctx,
requestHeader.getDefaultTopicQueueNums());
if (null == topicConfig) {
response.setCode(MQResponseCode.TOPIC_NOT_EXIST_VALUE);
response.setRemark("topic not exist, apply first please!");
return response;
}
}
// ���topicȨ��
if (!MixAll.isWriteable(topicConfig.getPerm())) {
response.setCode(MQResponseCode.NO_PERMISSION_VALUE);
response.setRemark("the topic[" + requestHeader.getTopic() + "] sending message is forbidden");
return response;
}
// ����������
int queueIdInt = requestHeader.getQueueId();
if (queueIdInt >= topicConfig.getWriteQueueNums()) {
String errorInfo =
"queueId[" + queueIdInt + "] is illagal, topicConfig.writeQueueNums: "
+ topicConfig.getWriteQueueNums() + " producer: " + ctx.channel().remoteAddress();
log.warn(errorInfo);
response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
response.setRemark(errorInfo);
return response;
}
// ���ָ��һ������
if (queueIdInt < 0) {
queueIdInt = Math.abs(this.random.nextInt()) % topicConfig.getWriteQueueNums();
}
int sysFlag = requestHeader.getSysFlag();
// ���ǩ������Ҫ��λ
if (TopicFilterType.MULTI_TAG == topicConfig.getTopicFilterType()) {
sysFlag |= MessageSysFlag.MultiTagsFlag;
}
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(requestHeader.getTopic());
msgInner.setBody(body);
msgInner.setFlag(requestHeader.getFlag());
msgInner.setProperties(MessageDecoder.string2messageProperties(requestHeader.getProperties()));
msgInner.setPropertiesString(requestHeader.getProperties());
msgInner.setTagsCode(MessageExtBrokerInner.tagsString2tagsCode(topicConfig.getTopicFilterType(),
msgInner.getTags()));
msgInner.setQueueId(queueIdInt);
msgInner.setSysFlag(sysFlag);
msgInner.setBornTimestamp(requestHeader.getBornTimestamp());
msgInner.setBornHost(ctx.channel().remoteAddress());
msgInner.setStoreHost(this.getStoreHost());
msgInner.setReconsumeTimes(0);
PutMessageResult putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner);
if (putMessageResult != null) {
boolean sendOK = false;
switch (putMessageResult.getPutMessageStatus()) {
// Success
case PUT_OK:
sendOK = true;
response.setCode(ResponseCode.SUCCESS_VALUE);
break;
case FLUSH_DISK_TIMEOUT:
response.setCode(MQResponseCode.FLUSH_DISK_TIMEOUT_VALUE);
sendOK = true;
break;
case FLUSH_SLAVE_TIMEOUT:
response.setCode(MQResponseCode.FLUSH_SLAVE_TIMEOUT_VALUE);
sendOK = true;
break;
case SLAVE_NOT_AVAILABLE:
response.setCode(MQResponseCode.SLAVE_NOT_AVAILABLE_VALUE);
sendOK = true;
break;
// Failed
case CREATE_MAPEDFILE_FAILED:
response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
response.setRemark("create maped file failed.");
break;
case MESSAGE_ILLEGAL:
response.setCode(MQResponseCode.MESSAGE_ILLEGAL_VALUE);
response.setRemark("the message is illegal, maybe length not matched.");
break;
case SERVICE_NOT_AVAILABLE:
response.setCode(MQResponseCode.SERVICE_NOT_AVAILABLE_VALUE);
response.setRemark("service not available now.");
break;
case UNKNOWN_ERROR:
response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
response.setRemark("UNKNOWN_ERROR");
break;
default:
response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
response.setRemark("UNKNOWN_ERROR DEFAULT");
break;
}
if (sendOK) {
response.setRemark(null);
responseHeader.setMsgId(putMessageResult.getAppendMessageResult().getMsgId());
responseHeader.setQueueId(queueIdInt);
responseHeader.setQueueOffset(putMessageResult.getAppendMessageResult().getLogicsOffset());
// ֱ�ӷ���
try {
ctx.write(response).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
log.error("SendMessageProcessor response to " + future.channel().remoteAddress()
+ " failed", future.cause());
log.error(request.toString());
log.error(response.toString());
}
}
});
}
catch (Throwable e) {
log.error("SendMessageProcessor process request over, but response failed", e);
log.error(request.toString());
log.error(response.toString());
}
this.brokerController.getPullRequestHoldService().notifyMessageArriving(requestHeader.getTopic(),
queueIdInt, putMessageResult.getAppendMessageResult().getLogicsOffset());
return null;
}
}
else {
response.setCode(ResponseCode.SYSTEM_ERROR_VALUE);
response.setRemark("store putMessage return null");
}
return response;
}
public SocketAddress getStoreHost() {
return storeHost;
}
}