/**
*
*/
package jframe.ext.dispatch;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.jms.pool.PooledConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jframe.core.conf.Config;
import jframe.core.dispatch.AbstractDispatcher;
import jframe.core.msg.Msg;
/**
* TODO 对于各种Msg类型的支持
* <p>
* 分发队列
* <li>dispatch发送队列名由Msg的key定义->d.mq.send.queue</li>
* <li>Msg没有定义发送队列,则默认队列名由MqConf的DefMqSendQueue定义</li>
* <li>Msg没有定义接收队列,则默认队列由MqConf的DefMqRecvQueue定义</li>
* </p>
* <p>
* Pub/Sub
* <li></li>
* <li></li>
* </p>
*
* @author dzh
* @date Oct 15, 2014 4:35:17 PM
* @since 1.0
*/
public class ActivemqDispatcher extends AbstractDispatcher {
static Logger LOG = LoggerFactory.getLogger(ActivemqDispatcher.class);
private PooledConnectionFactory poolFactory;
private BlockingQueue<Msg<?>> _queue;
static String MQ_FILE = "file.dispatcher.mq";
static final Boolean NON_TRANSACTED = false;
volatile boolean stop = false;
/**
* 消息Key
*/
static String Msg_SendQueue = "d.mq.send.queue";
/**
* 发送消息持久化
*/
static String Msg_DeliveryMode = "d.mq.delivery.mode";
// static String Msg_RecvQueue = "d.mq.recv.queue";
private ExecutorService workPool;
public ActivemqDispatcher(String id, Config config) {
super(id, config);
}
public void start() {
if (!initMqConf()) {
LOG.error("ActivemqDispatcher read conf error!");
return;
}
LOG.info("mq producer connect to {}", MqConf.MqUrl);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(MqConf.MqUrl);
connectionFactory.setUseAsyncSend(MqConf.UseAsyncSend);
poolFactory = new PooledConnectionFactory();
poolFactory.setConnectionFactory(connectionFactory);
poolFactory.setCreateConnectionOnStartup(MqConf.CreateConnectionOnStartup);
poolFactory.setMaxConnections(MqConf.MaxConnections);
poolFactory.setMaximumActiveSessionPerConnection(MqConf.MaximumActiveSessionPerConnection);
poolFactory.start();
_queue = new LinkedBlockingQueue<Msg<?>>();
workPool = new ThreadPoolExecutor(1, Runtime.getRuntime().availableProcessors() + 1, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
new Thread("DispatcherSendMqThread") {
public void run() {
LOG.info("DispatcherSendMqThread starting");
final BlockingQueue<Msg<?>> queue = _queue;
while (!stop) {
try {
final Msg<?> msg = queue.take();
if (msg != null) {
workPool.execute(new Runnable() {
public void run() {
try {
sendMq(msg);
} catch (Exception e) {
LOG.warn(e.getMessage());
}
}
});
}
if (MqConf.SendSleepTime > 0)
Thread.sleep(MqConf.SendSleepTime);
if (LOG.isDebugEnabled()) {
LOG.debug("Mq send msg -> {}, sum -> {}, date-> {}", msg.toString(), queue.size(),
new Date());
}
} catch (Exception e) {
LOG.warn(e.getMessage());
}
}
}
}.start();
new Thread("DispatcherRecvMqThread") {
public void run() {
LOG.info("DispatcherRecvMqThread starting");
Connection connection = null;
try {
connection = poolFactory.createConnection();
connection.start();
Session session = connection.createSession(NON_TRANSACTED, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(MqConf.DefMqRecvQueue);
final MessageConsumer consumer = session.createConsumer(destination);
final MsgTransfer msgTransfer = MqConf.Transfer;
while (!stop) {
try {
final Message message = consumer.receive(MqConf.ConsumerTimeout);
if (message != null)
workPool.execute(new Runnable() {
public void run() {
try {
if (message instanceof TextMessage) {
String text = ((TextMessage) message).getText();
dispatch(msgTransfer.decode(text));
if (LOG.isDebugEnabled()) {
LOG.debug("Mq dispatch msg -> {}, date-> {}", text, new Date());
}
}
} catch (Exception e) {
LOG.warn(e.getMessage());
}
}
});
if (MqConf.RecvSleepTime > 0)
Thread.sleep(MqConf.RecvSleepTime);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
consumer.close();
session.close();
} catch (Exception e) {
LOG.error(e.getMessage());
} finally {
if (connection != null)
try {
connection.close();
} catch (JMSException e) {
}
}
if (!stop) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
run();
}
}
}.start();
LOG.info("ActivemqDispatcher start successfully!");
}
private void sendMq(Msg<?> msg) {
Connection connection = null;
try {
connection = poolFactory.createConnection();
connection.start();
Session session = connection.createSession(NON_TRANSACTED, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(getSendQueueName(msg));
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(getDeliveryMode(msg));
TextMessage message = session.createTextMessage(MqConf.Transfer.encode(msg));
if (LOG.isDebugEnabled()) {
LOG.debug("produce msg {}", message.getText());
}
producer.send(message);
producer.close();
session.close();
} catch (Exception e) {
LOG.error(e.getMessage());
} finally {
if (connection != null)
try {
connection.close();
} catch (JMSException e) {
}
}
}
private int getDeliveryMode(Msg<?> msg) {
try {
if (msg.getMeta(Msg_DeliveryMode) == null) {
return javax.jms.DeliveryMode.PERSISTENT;
}
return Integer.parseInt(msg.getMeta(Msg_DeliveryMode));
} catch (Exception e) {
}
return javax.jms.DeliveryMode.PERSISTENT;
}
public String getSendQueueName(Msg<?> msg) {
String queue = msg.getMeta(Msg_SendQueue);
return queue == null ? MqConf.DefMqSendQueue : queue;
}
// public String getRecvQueueName(Msg<?> msg) {
// String queue = msg.getMeta(Msg_RecvQueue);
// return queue == null ? MqConf.DefMqRecvQueue : queue;
// }
private boolean initMqConf() {
Config config = getConfig();
try {
MqConf.init(config.getConfig(MQ_FILE));
return true;
} catch (Exception e) {
LOG.error(e.getMessage());
}
return false;
}
public void receive(final Msg<?> msg) {
if (msg == null || stop)
return;
try {
_queue.offer(msg, 60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
LOG.error(e.getMessage());
// TODO 数据丢失问题
}
}
/**
*
*/
@Override
public void close() {
stop = true;
super.close();
try {
if (poolFactory != null) {
poolFactory.stop();
}
if (workPool != null) {
workPool.shutdown();
workPool.awaitTermination(60, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
}
LOG.info("ActivemqDispatcher stopped!");
}
}