/* * 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.rocketmq.client.producer; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.QueryResult; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.message.*; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.exception.RemotingException; import java.util.List; /** * This class is the entry point for applications intending to send messages. * </p> * * It's fine to tune fields which exposes getter/setter methods, but keep in mind, all of them should work well out of * box for most scenarios. * </p> * * This class aggregates various <code>send</code> methods to deliver messages to brokers. Each of them has pros and * cons; you'd better understand strengths and weakness of them before actually coding. * </p> * * <p> * <strong>Thread Safety:</strong> After configuring and starting process, this class can be regarded as thread-safe * and used among multiple threads context. * </p> */ public class DefaultMQProducer extends ClientConfig implements MQProducer { /** * Wrapping internal implementations for virtually all methods presented in this class. */ protected final transient DefaultMQProducerImpl defaultMQProducerImpl; /** * Producer group conceptually aggregates all producer instances of exactly same role, which is particularly * important when transactional messages are involved. * </p> * * For non-transactional messages, it does not matter as long as it's unique per process. * </p> * * See {@linktourl http://rocketmq.incubator.apache.org/docs/core-concept/} for more discussion. */ private String producerGroup; /** * Just for testing or demo program * 目前会使用该变量去获取TopicRouteData * @see org.apache.rocketmq.client.impl.factory.MQClientInstance#updateTopicRouteInfoFromNameServer(String, boolean, DefaultMQProducer) */ private String createTopicKey = MixAll.DEFAULT_TOPIC; /** * Number of queues to create per default topic. */ private volatile int defaultTopicQueueNums = 4; /** * Timeout for sending messages. */ private int sendMsgTimeout = 3000; /** * Compress message body threshold, namely, message body larger than 4k will be compressed on default. */ private int compressMsgBodyOverHowmuch = 1024 * 4; /** * Maximum number of retry to perform internally before claiming sending failure in synchronous mode. * </p> * * This may potentially cause message duplication which is up to application developers to resolve. */ private int retryTimesWhenSendFailed = 2; /** * Maximum number of retry to perform internally before claiming sending failure in asynchronous mode. * </p> * * This may potentially cause message duplication which is up to application developers to resolve. */ private int retryTimesWhenSendAsyncFailed = 2; /** * Indicate whether to retry another broker on sending failure internally. */ // TODO 疑问:作用??? private boolean retryAnotherBrokerWhenNotStoreOK = false; /** * Maximum allowed message size in bytes. */ private int maxMessageSize = 1024 * 1024 * 4; // 4M /** * Default constructor. */ public DefaultMQProducer() { this(MixAll.DEFAULT_PRODUCER_GROUP, null); } /** * Constructor specifying both producer group and RPC hook. * * @param producerGroup Producer group, see the name-sake field. * @param rpcHook RPC hook to execute per each remoting command execution. */ public DefaultMQProducer(final String producerGroup, RPCHook rpcHook) { this.producerGroup = producerGroup; defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook); } /** * Constructor specifying producer group. * @param producerGroup Producer group, see the name-sake field. */ public DefaultMQProducer(final String producerGroup) { this(producerGroup, null); } /** * Constructor specifying the RPC hook. * @param rpcHook RPC hook to execute per each remoting command execution. */ public DefaultMQProducer(RPCHook rpcHook) { this(MixAll.DEFAULT_PRODUCER_GROUP, rpcHook); } /** * Start this producer instance. * </p> * * <strong> * Much internal initializing procedures are carried out to make this instance prepared, thus, it's a must to invoke * this method before sending or querying messages. * </strong> * </p> * * @throws MQClientException if there is any unexpected error. */ @Override public void start() throws MQClientException { this.defaultMQProducerImpl.start(); } /** * This method shuts down this producer instance and releases related resources. */ @Override public void shutdown() { this.defaultMQProducerImpl.shutdown(); } /** * Fetch message queues of topic <code>topic</code>, to which we may send/publish messages. * @param topic Topic to fetch. * @return List of message queues readily to send messages to * @throws MQClientException if there is any client error. */ @Override public List<MessageQueue> fetchPublishMessageQueues(String topic) throws MQClientException { return this.defaultMQProducerImpl.fetchPublishMessageQueues(topic); } /** * Send message in synchronous mode. This method returns only when the sending procedure totally completes. * </p> * * <strong>Warn:</strong> this method has internal retry-mechanism, that is, internal implementation will retry * {@link #retryTimesWhenSendFailed} times before claiming failure. As a result, multiple messages may potentially * delivered to broker(s). It's up to the application developers to resolve potential duplication issue. * * @param msg Message to send. * @return {@link SendResult} instance to inform senders details of the deliverable, say Message ID of the message, * {@link SendStatus} indicating broker storage/replication status, message queue sent to, etc. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws MQBrokerException if there is any error with broker. * @throws InterruptedException if the sending thread is interrupted. */ @Override public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.defaultMQProducerImpl.send(msg); } /** * Same to {@link #send(Message)} with send timeout specified in addition. * @param msg Message to send. * @param timeout send timeout. * @return {@link SendResult} instance to inform senders details of the deliverable, say Message ID of the message, * {@link SendStatus} indicating broker storage/replication status, message queue sent to, etc. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws MQBrokerException if there is any error with broker. * @throws InterruptedException if the sending thread is interrupted. */ @Override public SendResult send(Message msg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.defaultMQProducerImpl.send(msg, timeout); } /** * Send message to broker asynchronously. * </p> * * This method returns immediately. On sending completion, <code>sendCallback</code> will be executed. * </p> * * Similar to {@link #send(Message)}, internal implementation would potentially retry up to * {@link #retryTimesWhenSendAsyncFailed} times before claiming sending failure, which may yield message duplication * and application developers are the one to resolve this potential issue. * @param msg Message to send. * @param sendCallback Callback to execute on sending completed, either successful or unsuccessful. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void send(Message msg, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.send(msg, sendCallback); } /** * Same to {@link #send(Message, SendCallback)} with send timeout specified in addition. * @param msg message to send. * @param sendCallback Callback to execute. * @param timeout send timeout. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void send(Message msg, SendCallback sendCallback, long timeout) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.send(msg, sendCallback, timeout); } /** * Similar to <a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol">UDP</a>, this method won't wait for * acknowledgement from broker before return. Obviously, it has maximums throughput yet potentials of message loss. * @param msg Message to send. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void sendOneway(Message msg) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.sendOneway(msg); } /** * Same to {@link #send(Message)} with target message queue specified in addition. * @param msg Message to send. * @param mq Target message queue. * @return {@link SendResult} instance to inform senders details of the deliverable, say Message ID of the message, * {@link SendStatus} indicating broker storage/replication status, message queue sent to, etc. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws MQBrokerException if there is any error with broker. * @throws InterruptedException if the sending thread is interrupted. */ @Override public SendResult send(Message msg, MessageQueue mq) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.defaultMQProducerImpl.send(msg, mq); } /** * Same to {@link #send(Message)} with target message queue and send timeout specified. * * @param msg Message to send. * @param mq Target message queue. * @param timeout send timeout. * @return {@link SendResult} instance to inform senders details of the deliverable, say Message ID of the message, * {@link SendStatus} indicating broker storage/replication status, message queue sent to, etc. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws MQBrokerException if there is any error with broker. * @throws InterruptedException if the sending thread is interrupted. */ @Override public SendResult send(Message msg, MessageQueue mq, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.defaultMQProducerImpl.send(msg, mq, timeout); } /** * Same to {@link #send(Message, SendCallback)} with target message queue specified. * * @param msg Message to send. * @param mq Target message queue. * @param sendCallback Callback to execute on sending completed, either successful or unsuccessful. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void send(Message msg, MessageQueue mq, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.send(msg, mq, sendCallback); } /** * Same to {@link #send(Message, SendCallback)} with target message queue and send timeout specified. * @param msg Message to send. * @param mq Target message queue. * @param sendCallback Callback to execute on sending completed, either successful or unsuccessful. * @param timeout Send timeout. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void send(Message msg, MessageQueue mq, SendCallback sendCallback, long timeout) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.send(msg, mq, sendCallback, timeout); } /** * Same to {@link #sendOneway(Message)} with target message queue specified. * @param msg Message to send. * @param mq Target message queue. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void sendOneway(Message msg, MessageQueue mq) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.sendOneway(msg, mq); } /** * Same to {@link #send(Message)} with message queue selector specified. * * @param msg Message to send. * @param selector Message queue selector, through which we get target message queue to deliver message to. * @param arg Argument to work along with message queue selector. * @return {@link SendResult} instance to inform senders details of the deliverable, say Message ID of the message, * {@link SendStatus} indicating broker storage/replication status, message queue sent to, etc. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws MQBrokerException if there is any error with broker. * @throws InterruptedException if the sending thread is interrupted. */ @Override public SendResult send(Message msg, MessageQueueSelector selector, Object arg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.defaultMQProducerImpl.send(msg, selector, arg); } /** * Same to {@link #send(Message, MessageQueueSelector, Object)} with send timeout specified. * * @param msg Message to send. * @param selector Message queue selector, through which we get target message queue to deliver message to. * @param arg Argument to work along with message queue selector. * @param timeout Send timeout. * @return {@link SendResult} instance to inform senders details of the deliverable, say Message ID of the message, * {@link SendStatus} indicating broker storage/replication status, message queue sent to, etc. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws MQBrokerException if there is any error with broker. * @throws InterruptedException if the sending thread is interrupted. */ @Override public SendResult send(Message msg, MessageQueueSelector selector, Object arg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.defaultMQProducerImpl.send(msg, selector, arg, timeout); } /** * Same to {@link #send(Message, SendCallback)} with message queue selector specified. * * @param msg Message to send. * @param selector Message selector through which to get target message queue. * @param arg Argument used along with message queue selector. * @param sendCallback callback to execute on sending completion. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void send(Message msg, MessageQueueSelector selector, Object arg, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.send(msg, selector, arg, sendCallback); } /** * Same to {@link #send(Message, MessageQueueSelector, Object, SendCallback)} with timeout specified. * * @param msg Message to send. * @param selector Message selector through which to get target message queue. * @param arg Argument used along with message queue selector. * @param sendCallback callback to execute on sending completion. * @param timeout Send timeout. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void send(Message msg, MessageQueueSelector selector, Object arg, SendCallback sendCallback, long timeout) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.send(msg, selector, arg, sendCallback, timeout); } /** * Same to {@link #sendOneway(Message)} with message queue selector specified. * @param msg Message to send. * @param selector Message queue selector, through which to determine target message queue to deliver message * @param arg Argument used along with message queue selector. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public void sendOneway(Message msg, MessageQueueSelector selector, Object arg) throws MQClientException, RemotingException, InterruptedException { this.defaultMQProducerImpl.sendOneway(msg, selector, arg); } /** * This method is to send transactional messages. * * @param msg Transactional message to send. * @param tranExecuter local transaction executor. * @param arg Argument used along with local transaction executor. * @return Transaction result. * @throws MQClientException if there is any client error. */ @Override public TransactionSendResult sendMessageInTransaction(Message msg, LocalTransactionExecuter tranExecuter, final Object arg) throws MQClientException { throw new RuntimeException("sendMessageInTransaction not implement, please use TransactionMQProducer class"); } /** * Create a topic on broker. * @param key accesskey * @param newTopic topic name * @param queueNum topic's queue number * @throws MQClientException if there is any client error. */ @Override public void createTopic(String key, String newTopic, int queueNum) throws MQClientException { createTopic(key, newTopic, queueNum, 0); } /** * Create a topic on broker. * @param key accesskey * @param newTopic topic name * @param queueNum topic's queue number * @param topicSysFlag topic system flag * @throws MQClientException if there is any client error. */ @Override public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) throws MQClientException { this.defaultMQProducerImpl.createTopic(key, newTopic, queueNum, topicSysFlag); } /** * Search consume queue offset of the given time stamp. * @param mq Instance of MessageQueue * @param timestamp from when in milliseconds. * @return Consume queue offset. * @throws MQClientException if there is any client error. */ @Override public long searchOffset(MessageQueue mq, long timestamp) throws MQClientException { return this.defaultMQProducerImpl.searchOffset(mq, timestamp); } /** * Query maximum offset of the given message queue. * * @param mq Instance of MessageQueue * @return maximum offset of the given consume queue. * @throws MQClientException if there is any client error. */ @Override public long maxOffset(MessageQueue mq) throws MQClientException { return this.defaultMQProducerImpl.maxOffset(mq); } /** * Query minimum offset of the given message queue. * @param mq Instance of MessageQueue * @return minimum offset of the given message queue. * @throws MQClientException if there is any client error. */ @Override public long minOffset(MessageQueue mq) throws MQClientException { return this.defaultMQProducerImpl.minOffset(mq); } /** * Query earliest message store time. * @param mq Instance of MessageQueue * @return earliest message store time. * @throws MQClientException if there is any client error. */ @Override public long earliestMsgStoreTime(MessageQueue mq) throws MQClientException { return this.defaultMQProducerImpl.earliestMsgStoreTime(mq); } /** * Query message of the given offset message ID. * @param offsetMsgId message id * @return Message specified. * @throws MQBrokerException if there is any broker error. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public MessageExt viewMessage(String offsetMsgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { return this.defaultMQProducerImpl.viewMessage(offsetMsgId); } /** * Query message by key. * @param topic message topic * @param key message key index word * @param maxNum max message number * @param begin from when * @param end to when * @return QueryResult instance contains matched messages. * @throws MQClientException if there is any client error. * @throws InterruptedException if the thread is interrupted. */ @Override public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end) throws MQClientException, InterruptedException { return this.defaultMQProducerImpl.queryMessage(topic, key, maxNum, begin, end); } /** * Query message of the given message ID. * * @param topic Topic * @param msgId Message ID * @return Message specified. * @throws MQBrokerException if there is any broker error. * @throws MQClientException if there is any client error. * @throws RemotingException if there is any network-tier error. * @throws InterruptedException if the sending thread is interrupted. */ @Override public MessageExt viewMessage(String topic, String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { try { MessageId oldMsgId = MessageDecoder.decodeMessageId(msgId); return this.viewMessage(msgId); } catch (Exception e) { } return this.defaultMQProducerImpl.queryMessageByUniqKey(topic, msgId); } public String getProducerGroup() { return producerGroup; } public void setProducerGroup(String producerGroup) { this.producerGroup = producerGroup; } public String getCreateTopicKey() { return createTopicKey; } public void setCreateTopicKey(String createTopicKey) { this.createTopicKey = createTopicKey; } public int getSendMsgTimeout() { return sendMsgTimeout; } public void setSendMsgTimeout(int sendMsgTimeout) { this.sendMsgTimeout = sendMsgTimeout; } public int getCompressMsgBodyOverHowmuch() { return compressMsgBodyOverHowmuch; } public void setCompressMsgBodyOverHowmuch(int compressMsgBodyOverHowmuch) { this.compressMsgBodyOverHowmuch = compressMsgBodyOverHowmuch; } public DefaultMQProducerImpl getDefaultMQProducerImpl() { return defaultMQProducerImpl; } public boolean isRetryAnotherBrokerWhenNotStoreOK() { return retryAnotherBrokerWhenNotStoreOK; } public void setRetryAnotherBrokerWhenNotStoreOK(boolean retryAnotherBrokerWhenNotStoreOK) { this.retryAnotherBrokerWhenNotStoreOK = retryAnotherBrokerWhenNotStoreOK; } public int getMaxMessageSize() { return maxMessageSize; } public void setMaxMessageSize(int maxMessageSize) { this.maxMessageSize = maxMessageSize; } public int getDefaultTopicQueueNums() { return defaultTopicQueueNums; } public void setDefaultTopicQueueNums(int defaultTopicQueueNums) { this.defaultTopicQueueNums = defaultTopicQueueNums; } public int getRetryTimesWhenSendFailed() { return retryTimesWhenSendFailed; } public void setRetryTimesWhenSendFailed(int retryTimesWhenSendFailed) { this.retryTimesWhenSendFailed = retryTimesWhenSendFailed; } public boolean isSendMessageWithVIPChannel() { return isVipChannelEnabled(); } public void setSendMessageWithVIPChannel(final boolean sendMessageWithVIPChannel) { this.setVipChannelEnabled(sendMessageWithVIPChannel); } public long[] getNotAvailableDuration() { return this.defaultMQProducerImpl.getNotAvailableDuration(); } public void setNotAvailableDuration(final long[] notAvailableDuration) { this.defaultMQProducerImpl.setNotAvailableDuration(notAvailableDuration); } public long[] getLatencyMax() { return this.defaultMQProducerImpl.getLatencyMax(); } public void setLatencyMax(final long[] latencyMax) { this.defaultMQProducerImpl.setLatencyMax(latencyMax); } public boolean isSendLatencyFaultEnable() { return this.defaultMQProducerImpl.isSendLatencyFaultEnable(); } public void setSendLatencyFaultEnable(final boolean sendLatencyFaultEnable) { this.defaultMQProducerImpl.setSendLatencyFaultEnable(sendLatencyFaultEnable); } public int getRetryTimesWhenSendAsyncFailed() { return retryTimesWhenSendAsyncFailed; } public void setRetryTimesWhenSendAsyncFailed(final int retryTimesWhenSendAsyncFailed) { this.retryTimesWhenSendAsyncFailed = retryTimesWhenSendAsyncFailed; } }