/** * $Id: DefaultMQPullConsumerImpl.java 1831 2013-05-16 01:39:51Z shijia.wxr $ */ package com.alibaba.rocketmq.client.impl.consumer; import java.nio.ByteBuffer; import java.util.HashSet; import java.util.List; import java.util.Set; import com.alibaba.rocketmq.client.QueryResult; import com.alibaba.rocketmq.client.consumer.DefaultMQPullConsumer; import com.alibaba.rocketmq.client.consumer.PullCallback; import com.alibaba.rocketmq.client.consumer.PullResult; import com.alibaba.rocketmq.client.consumer.PullStatus; import com.alibaba.rocketmq.client.exception.MQBrokerException; import com.alibaba.rocketmq.client.exception.MQClientException; import com.alibaba.rocketmq.client.impl.CommunicationMode; import com.alibaba.rocketmq.client.impl.FindBrokerResult; import com.alibaba.rocketmq.client.impl.MQClientManager; import com.alibaba.rocketmq.client.impl.factory.MQClientFactory; import com.alibaba.rocketmq.common.MessageDecoder; import com.alibaba.rocketmq.common.MessageExt; import com.alibaba.rocketmq.common.MessageQueue; import com.alibaba.rocketmq.common.ServiceState; import com.alibaba.rocketmq.common.TopicFilterType; import com.alibaba.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader; import com.alibaba.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import com.alibaba.rocketmq.common.protocol.heartbeat.ConsumeType; import com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel; import com.alibaba.rocketmq.common.protocol.heartbeat.SubscriptionData; import com.alibaba.rocketmq.common.sysflag.PullSysFlag; import com.alibaba.rocketmq.remoting.exception.RemotingException; /** * ����Consumerʵ�� * * @author vintage.wang@gmail.com shijia.wxr@taobao.com */ public class DefaultMQPullConsumerImpl implements MQConsumerInner { private ServiceState serviceState = ServiceState.CREATE_JUST; private final DefaultMQPullConsumer defaultMQPullConsumer; private MQClientFactory mQClientFactory; private PullAPIWrapper pullAPIWrapper; public DefaultMQPullConsumerImpl(final DefaultMQPullConsumer defaultMQPullConsumer) { this.defaultMQPullConsumer = defaultMQPullConsumer; } public void start() throws MQClientException { switch (this.serviceState) { case CREATE_JUST: this.serviceState = ServiceState.RUNNING; this.mQClientFactory = MQClientManager.getInstance().getAndCreateMQClientFactory( this.defaultMQPullConsumer.getMQClientConfig()); this.pullAPIWrapper = new PullAPIWrapper(// mQClientFactory,// this.defaultMQPullConsumer.getConsumerGroup(),// this.defaultMQPullConsumer.getConsumeFromWhichNode()); boolean registerOK = mQClientFactory.registerConsumer(this.defaultMQPullConsumer.getConsumerGroup(), this); if (!registerOK) { this.serviceState = ServiceState.CREATE_JUST; throw new MQClientException("The consumer group[" + this.defaultMQPullConsumer.getConsumerGroup() + "] has created already, specifed another name please.", null); } mQClientFactory.start(); break; case RUNNING: break; case SHUTDOWN_ALREADY: break; default: break; } } public void shutdown() { switch (this.serviceState) { case CREATE_JUST: break; case RUNNING: this.serviceState = ServiceState.SHUTDOWN_ALREADY; this.mQClientFactory.unregisterConsumer(this.defaultMQPullConsumer.getConsumerGroup()); this.mQClientFactory.shutdown(); break; case SHUTDOWN_ALREADY: break; default: break; } } private void makeSureStateOK() throws MQClientException { if (this.serviceState != ServiceState.RUNNING) { throw new MQClientException("The producer service state not OK", null); } } public void createTopic(String key, String newTopic, int queueNum, TopicFilterType topicFilterType, boolean order) throws MQClientException { this.makeSureStateOK(); this.mQClientFactory.getMQAdminImpl().createTopic(key, newTopic, queueNum, topicFilterType, order); } public List<MessageQueue> fetchPublishMessageQueues(String topic) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().fetchPublishMessageQueues(topic); } public long searchOffset(MessageQueue mq, long timestamp) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().searchOffset(mq, timestamp); } public long getMaxOffset(MessageQueue mq) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().getMaxOffset(mq); } public long getMinOffset(MessageQueue mq) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().getMinOffset(mq); } public long getEarliestMsgStoreTime(MessageQueue mq) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().getEarliestMsgStoreTime(mq); } public MessageExt viewMessage(String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().viewMessage(msgId); } public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end) throws MQClientException, InterruptedException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().queryMessage(topic, key, maxNum, begin, end); } private PullResult pullSyncImpl(MessageQueue mq, String subExpression, long offset, int maxNums, boolean block) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { this.makeSureStateOK(); if (null == mq) { throw new MQClientException("mq is null", null); } if (offset < 0) { throw new MQClientException("offset < 0", null); } if (maxNums <= 0) { throw new MQClientException("maxNums <= 0", null); } int sysFlag = PullSysFlag.buildSysFlag(false, block, true); String subExpressionInner = subExpression != null ? subExpression : SubscriptionData.SUB_ALL; long timeoutMillis = block ? this.defaultMQPullConsumer.getConsumerTimeoutMillisWhenSuspend() : this.defaultMQPullConsumer.getConsumerPullTimeoutMillis(); PullResult pullResult = this.pullAPIWrapper.pullKernelImpl(mq, subExpressionInner, offset, maxNums, sysFlag, 0, this.defaultMQPullConsumer.getBrokerSuspendMaxTimeMillis(), timeoutMillis, CommunicationMode.SYNC, null); return this.processPullResult(mq, pullResult); } /** * ����ȡ������д�����Ҫ����Ϣ�����л� */ private PullResult processPullResult(final MessageQueue mq, final PullResult pullResult) { PullResultExt pullResultExt = (PullResultExt) pullResult; this.pullAPIWrapper.updatePullFromWhichNode(mq, pullResultExt.isSuggestPullingFromSlave()); if (PullStatus.FOUND == pullResult.getPullStatus()) { ByteBuffer byteBuffer = ByteBuffer.wrap(pullResultExt.getMessageBinary()); List<MessageExt> msgList = MessageDecoder.decodes(byteBuffer); pullResultExt.setMsgFoundList(msgList); } // ��GC�ͷ��ڴ� pullResultExt.setMessageBinary(null); return pullResult; } private void pullAsyncImpl(// final MessageQueue mq,// final String subExpression,// final long offset,// final int maxNums,// final PullCallback pullCallback,// final boolean block// ) throws MQClientException, RemotingException, InterruptedException { this.makeSureStateOK(); if (null == mq) { throw new MQClientException("mq is null", null); } if (offset < 0) { throw new MQClientException("offset < 0", null); } if (maxNums <= 0) { throw new MQClientException("maxNums <= 0", null); } if (null == pullCallback) { throw new MQClientException("pullCallback is null", null); } try { int sysFlag = PullSysFlag.buildSysFlag(false, block, true); String subExpressionInner = subExpression != null ? subExpression : SubscriptionData.SUB_ALL; long timeoutMillis = block ? this.defaultMQPullConsumer.getConsumerTimeoutMillisWhenSuspend() : this.defaultMQPullConsumer.getConsumerPullTimeoutMillis(); this.pullAPIWrapper.pullKernelImpl(mq, subExpressionInner, offset, maxNums, sysFlag, 0, this.defaultMQPullConsumer.getBrokerSuspendMaxTimeMillis(), timeoutMillis, CommunicationMode.ASYNC, new PullCallback() { @Override public void onSuccess(PullResult pullResult) { pullCallback.onSuccess(DefaultMQPullConsumerImpl.this.processPullResult(mq, pullResult)); } @Override public void onException(Throwable e) { pullCallback.onException(e); } }); } catch (MQBrokerException e) { throw new MQClientException("pullAsync unknow exception", e); } } public PullResult pull(MessageQueue mq, String subExpression, long offset, int maxNums) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.pullSyncImpl(mq, subExpression, offset, maxNums, false); } public PullResult pullBlockIfNotFound(MessageQueue mq, String subExpression, long offset, int maxNums) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.pullSyncImpl(mq, subExpression, offset, maxNums, true); } public void pull(MessageQueue mq, String subExpression, long offset, int maxNums, PullCallback pullCallback) throws MQClientException, RemotingException, InterruptedException { this.pullAsyncImpl(mq, subExpression, offset, maxNums, pullCallback, false); } public void pullBlockIfNotFound(MessageQueue mq, String subExpression, long offset, int maxNums, PullCallback pullCallback) throws MQClientException, RemotingException, InterruptedException { this.pullAsyncImpl(mq, subExpression, offset, maxNums, pullCallback, true); } public void updateConsumeOffset(MessageQueue mq, long offset) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { FindBrokerResult findBrokerResult = this.mQClientFactory.findBrokerAddressInAdmin(mq.getBrokerName()); if (null == findBrokerResult) { // TODO �˴����ܶ�Name Serverѹ��������Ҫ���� this.mQClientFactory.updateTopicRouteInfoFromNameServer(mq.getTopic()); findBrokerResult = this.mQClientFactory.findBrokerAddressInAdmin(mq.getBrokerName()); } if (findBrokerResult != null) { UpdateConsumerOffsetRequestHeader requestHeader = new UpdateConsumerOffsetRequestHeader(); requestHeader.setTopic(mq.getTopic()); requestHeader.setConsumerGroup(this.defaultMQPullConsumer.getConsumerGroup()); requestHeader.setQueueId(mq.getQueueId()); requestHeader.setCommitOffset(offset); this.mQClientFactory.getMQClientAPIImpl().updateConsumerOffset(findBrokerResult.getBrokerAddr(), requestHeader, 1000 * 5); } else { throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null); } } public long fetchConsumeOffset(MessageQueue mq) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { FindBrokerResult findBrokerResult = this.mQClientFactory.findBrokerAddressInAdmin(mq.getBrokerName()); if (null == findBrokerResult) { // TODO �˴����ܶ�Name Serverѹ��������Ҫ���� this.mQClientFactory.updateTopicRouteInfoFromNameServer(mq.getTopic()); findBrokerResult = this.mQClientFactory.findBrokerAddressInAdmin(mq.getBrokerName()); } if (findBrokerResult != null) { QueryConsumerOffsetRequestHeader requestHeader = new QueryConsumerOffsetRequestHeader(); requestHeader.setTopic(mq.getTopic()); requestHeader.setConsumerGroup(this.defaultMQPullConsumer.getConsumerGroup()); requestHeader.setQueueId(mq.getQueueId()); return this.mQClientFactory.getMQClientAPIImpl().queryConsumerOffset( findBrokerResult.getBrokerAddr(), requestHeader, 1000 * 5); } else { throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null); } } public List<MessageQueue> fetchMessageQueuesInBalance(String topic) { // TODO Auto-generated method stub return null; } public List<MessageQueue> fetchSubscribeMessageQueues(String topic) throws MQClientException { return this.mQClientFactory.getMQAdminImpl().fetchSubscribeMessageQueues(topic); } @Override public MessageModel getMessageModel() { return MessageModel.UNKNOWNS; } @Override public ConsumeType getConsumeType() { return ConsumeType.CONSUME_ACTIVELY; } @Override public Set<SubscriptionData> getMQSubscriptions() { Set<SubscriptionData> result = new HashSet<SubscriptionData>(); Set<String> topics = this.defaultMQPullConsumer.getRegisterTopics(); if (topics != null) { synchronized (topics) { for (String t : topics) { // TODO SubscriptionData ms = new SubscriptionData(t, null, null, true); result.add(ms); } } } return result; } @Override public String getGroupName() { return this.defaultMQPullConsumer.getConsumerGroup(); } }