package org.zbus.server.mq; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import org.zbus.common.logging.Logger; import org.zbus.common.logging.LoggerFactory; import org.zbus.common.protocol.ConsumerInfo; import org.zbus.common.remoting.Message; import org.zbus.common.remoting.nio.Session; public class PubsubQueue extends MessageQueue { private static final long serialVersionUID = -593851217778104787L; private static final Logger log = LoggerFactory.getLogger(PubsubQueue.class); protected final BlockingQueue<Message> msgQ = new LinkedBlockingQueue<Message>(); //保留所有的订阅Session transient ConcurrentMap<String, PullSession> sessMap = new ConcurrentHashMap<String, PullSession>(); public PubsubQueue(String broker, String name, ExecutorService executor, int mode){ super(broker, name, executor, mode); } public void produce(Message msg, Session sess) throws IOException{ String msgId = msg.getMsgId(); if(msg.isAck()){ ReplyHelper.reply200(msgId, sess); } msgQ.offer(msg); this.dispatch(); } @Override public void consume(Message msg, Session sess) throws IOException{ PullSession pull = sessMap.get(sess.id()); if(pull != null){ pull.setPullMsg(msg); } else { pull = new PullSession(sess, msg); sessMap.putIfAbsent(sess.id(), pull); } this.dispatch(); } @Override public void cleanSession() { Iterator<Entry<String, PullSession>> iter = sessMap.entrySet().iterator(); while(iter.hasNext()){ PullSession ps = iter.next().getValue(); if(!ps.session.isActive()){ iter.remove(); } } } @Override void doDispatch() throws IOException{ Message msg = null; while((msg = msgQ.poll()) != null){ String topic = msg.getTopic(); Iterator<Entry<String, PullSession>> iter = sessMap.entrySet().iterator(); while(iter.hasNext()){ PullSession sess = iter.next().getValue(); if(sess == null || !sess.getSession().isActive()){ iter.remove(); continue; } if(sess.isTopicMatched(topic)){ Message copy = Message.copyWithoutBody(msg); prepareMessageStatus(copy); sess.getMsgQ().offer(copy); } } } Iterator<Entry<String, PullSession>> iter = sessMap.entrySet().iterator(); while(iter.hasNext()){ PullSession sess = iter.next().getValue(); if(sess == null || !sess.getSession().isActive()){ iter.remove(); continue; } try{ sess.pullMsgLock.lock(); Message pullMsg = sess.getPullMsg(); if(pullMsg == null) continue; //无消息读取请求 msg = sess.getMsgQ().poll(); if(msg == null) continue; //消息未到达 sess.setPullMsg(null); msg.setStatus("200"); //支持浏览器 msg.setMsgIdRaw(pullMsg.getMsgId()); //保留原始消息ID msg.setMsgId(pullMsg.getMsgId()); //配对订阅消息! sess.getSession().write(msg); } catch(IOException ex){ log.error(ex.getMessage(), ex); } finally{ sess.pullMsgLock.unlock(); } } } public List<ConsumerInfo> getConsumerInfoList() { List<ConsumerInfo> res = new ArrayList<ConsumerInfo>(); Iterator<Entry<String, PullSession>> iter = sessMap.entrySet().iterator(); while(iter.hasNext()){ PullSession value = iter.next().getValue(); Session sess = value.getSession(); ConsumerInfo info = new ConsumerInfo(); info.setStatus(sess.getStatus().toString()); info.setRemoteAddr(sess.getRemoteAddress()); if(value.getTopics() != null){ info.setTopics(new ArrayList<String>(value.getTopics())); } res.add(info); } return res; } @Override public int getMessageQueueSize() { return this.msgQ.size(); } }