package ddth.dasp.hetty.qnt.redis; import java.util.concurrent.TimeUnit; import ddth.dasp.common.DaspGlobal; import ddth.dasp.common.redis.IMessageListener; import ddth.dasp.common.redis.IRedisClient; import ddth.dasp.common.redis.IRedisClientFactory; import ddth.dasp.common.redis.PoolConfig; import ddth.dasp.hetty.front.AbstractHettyResponseService; import ddth.dasp.hetty.message.IMessageFactory; import ddth.dasp.hetty.message.IResponse; /* * TODO: what would happen if a message comes when onMessage() is busy? * @see http://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/ */ public class RedisResponseService extends AbstractHettyResponseService implements IMessageListener { private IRedisClientFactory redisClientFactory; private String redisHost = "localhost"; private int redisPort = IRedisClient.DEFAULT_REDIS_PORT; private String redisUsername, redisPassword; private PoolConfig poolConfig; private IMessageFactory messageFactory; private String topicName; private boolean _destroyed = false, _listening = false; protected String getTopicName() { return topicName; } public RedisResponseService setTopicName(String topicName) { this.topicName = topicName; return this; } protected IRedisClientFactory getRedisClientFactory() { return redisClientFactory; } public RedisResponseService setRedisClientFactory(IRedisClientFactory redisClientFactory) { this.redisClientFactory = redisClientFactory; return this; } protected String getRedisHost() { return redisHost; } public RedisResponseService setRedisHost(String redisHost) { this.redisHost = redisHost; return this; } protected int getRedisPort() { return redisPort; } public RedisResponseService setRedisPort(int redisPort) { this.redisPort = redisPort; return this; } protected String getRedisUsername() { return redisUsername; } public RedisResponseService setRedisUsername(String redisUsername) { this.redisUsername = redisUsername; return this; } protected String getRedisPassword() { return redisPassword; } public RedisResponseService setRedisPassword(String redisPassword) { this.redisPassword = redisPassword; return this; } protected PoolConfig getPoolConfig() { return poolConfig; } public RedisResponseService setPoolConfig(PoolConfig poolConfig) { this.poolConfig = poolConfig; return this; } protected IMessageFactory getMessageFactory() { return messageFactory; } public RedisResponseService setMessageFactory(IMessageFactory messageFactory) { this.messageFactory = messageFactory; return this; } private class MessageListenerKeeper implements Runnable { private IMessageListener messageListener; public MessageListenerKeeper(IMessageListener messageListener) { this.messageListener = messageListener; } @Override public void run() { if (!_destroyed) { try { if (!_listening) { IRedisClient redisClient = getRedisClient(); if (redisClient != null) { _listening = true; redisClient.subscribe(topicName, messageListener); } } } finally { DaspGlobal.getScheduler().schedule(this, 5000, TimeUnit.MILLISECONDS); } } } } public void init() { Runnable command = new MessageListenerKeeper(this); DaspGlobal.getScheduler().schedule(command, 2000, TimeUnit.MILLISECONDS); } public void destroy() { _destroyed = true; try { unsubscribe(topicName); } finally { returnRedisClient(); } } private IRedisClient _redisClient; synchronized private IRedisClient getRedisClient() { if (_redisClient == null) { _redisClient = redisClientFactory.getRedisClient(redisHost, redisPort, redisUsername, redisPassword, poolConfig); } return _redisClient; } synchronized private void returnRedisClient() { try { redisClientFactory.returnRedisClient(_redisClient); } finally { _redisClient = null; } } /** * {@inheritDoc} */ @Override public void unsubscribe(String channel) { try { if (_redisClient != null) { _redisClient.unsubscribe(channel, this); } } finally { _listening = false; } } /** * {@inheritDoc} */ @Override public void onMessage(String channel, byte[] message) { IResponse response = messageFactory.deserializeResponse((byte[]) message); writeResponse(response); } }