package storm.applications.spout;
import backtype.storm.utils.Utils;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
import storm.applications.constants.BaseConstants.BaseConf;
import storm.applications.spout.parser.Parser;
import storm.applications.util.config.ClassLoaderUtils;
import storm.applications.util.stream.StreamValues;
/**
* Adapted from https://github.com/sorenmacbeth/storm-redis-pubsub
*/
public class RedisSpout extends AbstractSpout {
private static final Logger LOG = LoggerFactory.getLogger(RedisSpout.class);
private LinkedBlockingQueue<String> queue;
private JedisPool pool;
private Parser parser;
@Override
protected void initialize() {
String parserClass = config.getString(getConfigKey(BaseConf.SPOUT_PARSER));
String host = config.getString(getConfigKey(BaseConf.REDIS_HOST));
String pattern = config.getString(getConfigKey(BaseConf.REDIS_PATTERN));
int port = config.getInt(getConfigKey(BaseConf.REDIS_PORT));
int queueSize = config.getInt(getConfigKey(BaseConf.REDIS_QUEUE_SIZE));
parser = (Parser) ClassLoaderUtils.newInstance(parserClass, "parser", LOG);
parser.initialize(config);
queue = new LinkedBlockingQueue<>(queueSize);
pool = new JedisPool(new JedisPoolConfig(), host, port);
ListenerThread listener = new ListenerThread(queue, pool, pattern);
listener.start();
}
@Override
public void nextTuple() {
String message = queue.poll();
if (message == null) {
Utils.sleep(50);
} else {
List<StreamValues> tuples = parser.parse(message);
if (tuples != null) {
for (StreamValues values : tuples)
collector.emit(values.getStreamId(), values);
}
}
}
private class ListenerThread extends Thread {
private LinkedBlockingQueue<String> queue;
private JedisPool pool;
private String pattern;
public ListenerThread(LinkedBlockingQueue<String> queue, JedisPool pool, String pattern) {
this.queue = queue;
this.pool = pool;
this.pattern = pattern;
}
@Override
public void run() {
Jedis jedis = pool.getResource();
try {
jedis.psubscribe(new JedisListener(queue), pattern);
} finally {
pool.returnResource(jedis);
}
}
}
private class JedisListener extends JedisPubSub {
private LinkedBlockingQueue<String> queue;
public JedisListener(LinkedBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void onMessage(String channel, String message) {
queue.offer(message);
}
@Override
public void onPMessage(String pattern, String channel, String message) {
queue.offer(message);
}
@Override
public void onPSubscribe(String channel, int subscribedChannels) { }
@Override
public void onPUnsubscribe(String channel, int subscribedChannels) { }
@Override
public void onSubscribe(String channel, int subscribedChannels) { }
@Override
public void onUnsubscribe(String channel, int subscribedChannels) { }
}
}