All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zbus.mq.Consumer Maven / Gradle / Ivy

/**
 * The MIT License (MIT)
 * Copyright (c) 2009-2015 HONG LEIMING
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.zbus.mq;

import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.ClosedByInterruptException;

import org.zbus.broker.Broker;
import org.zbus.kit.log.Logger;
import org.zbus.mq.Protocol.MqMode;
import org.zbus.net.http.Message;
import org.zbus.net.http.Message.MessageHandler;
import org.zbus.net.http.MessageClient;

public class Consumer extends MqAdmin implements Closeable {
	private static final Logger log = Logger.getLogger(Consumer.class);

	private MessageClient client; // 消费者拥有一个物理链接
	private String topic = null; // 为发布订阅者的主题,当Consumer的模式为发布订阅时候起作用
	private int consumeTimeout = 10000; //ms
	public Consumer(Broker broker, String mq, MqMode... mode) {
		super(broker, mq, mode);
	}

	public Consumer(MqConfig config) {
		super(config);
		this.topic = config.getTopic();
	}

	private void ensureClient() throws IOException{
		if(this.client == null){
    		synchronized (this) {
				if(this.client == null){
					this.client = broker.getClient(brokerHint()); 
				}
			} 
    	}
	}
	
	public Message recv(int timeout) throws IOException, InterruptedException {
		ensureClient();
		
		Message req = new Message();
		req.setCmd(Protocol.Consume);
		req.setMq(mq);
		if (MqMode.isEnabled(this.mode, MqMode.PubSub)) {
			if (this.topic != null) {
				req.setTopic(this.topic);
			}
		}

		Message res = null;
		try {
			res = client.invokeSync(req, timeout);
			if (res != null && res.isStatus404()) {
				if (!this.createMQ()) {
					throw new IllegalStateException("register error");
				}
				return recv(timeout);
			}
			if(res != null){
				res.setId(res.getRawId());
				res.removeHead(Message.RAWID);
			}
		} catch (ClosedByInterruptException e) {
			throw new InterruptedException(e.getMessage());
		} catch (IOException e) { 
			log.error(e.getMessage(), e);
			try {
				broker.closeClient(client);
				client = broker.getClient(brokerHint());
			} catch (IOException ex) {
				log.error(ex.getMessage(), ex);
			}
		}
		return res;
	}

	public void close() throws IOException {
		stop();
		if (this.client != null) {
			this.broker.closeClient(this.client);
		} 
	}

	@Override
	protected Message invokeCreateMQ(Message req) throws IOException,
			InterruptedException {
		ensureClient();
		return client.invokeSync(req);
	}
	
	public void routeMessage(Message msg) throws IOException {
		ensureClient();
		msg.setCmd(Protocol.Route);
		msg.setAck(false); 
		
		client.send(msg);
	}

	public String getTopic() {
		return topic;
	}

	public void setTopic(String topic) {
		if (!MqMode.isEnabled(this.mode, MqMode.PubSub)) {
			throw new IllegalStateException("topic require PubSub mode");
		}
		this.topic = topic;
	} 
	
	private volatile Thread consumerThread = null;
	private volatile MessageHandler consumerHandler;
	private final Runnable consumerTask = new Runnable() {
		@Override
		public void run() { 
			while(true){
				try {
					final Message msg;
					try { 
						msg = recv(consumeTimeout); 
					} catch (InterruptedException e) { 
						break;
					}
					if(msg == null) continue;
					if(consumerHandler == null){
						log.warn("Missing consumer MessageHandler, call onMessage first");
						continue;
					}
					try {
						consumerHandler.handle(msg, client.getSession());
					} catch (IOException e) {
						log.error(e.getMessage(), e);
					}  
				} catch (IOException e) { 
					log.error(e.getMessage(), e);
				} 
			}
		}
	};
	
	public void onMessage(final MessageHandler handler) throws IOException{
		this.consumerHandler = handler;
	}
	
	public void stop(){
		if(consumerThread != null){
			consumerThread.interrupt();
			consumerThread = null;
		}
		try {
			if (this.client != null) {
				this.broker.closeClient(this.client);
			} 
			client = null;
		} catch (IOException e) {
			log.error(e.getMessage(), e); 
		}
	}
	
	public void start(){
		if(consumerThread == null){
			consumerThread = new Thread(consumerTask);  
		}
		
		if(consumerThread.isAlive()) return;
		consumerThread.start();
	}
	
	public void setConsumeTimeout(int consumeTimeout) {
		this.consumeTimeout = consumeTimeout;
	} 
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy