package udacity.storm; import backtype.storm.Config; import backtype.storm.LocalCluster; import backtype.storm.StormSubmitter; import backtype.storm.spout.SpoutOutputCollector; import backtype.storm.task.OutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.testing.TestWordSpout; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.topology.TopologyBuilder; import backtype.storm.topology.base.BaseRichSpout; import backtype.storm.topology.base.BaseRichBolt; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import backtype.storm.utils.Utils; import twitter4j.conf.ConfigurationBuilder; import twitter4j.TwitterStream; import twitter4j.TwitterStreamFactory; import twitter4j.Status; import twitter4j.StatusDeletionNotice; import twitter4j.StatusListener; import twitter4j.StallWarning; import java.util.HashMap; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; /** * A spout that uses Twitter streaming API for continuously * getting tweets */ public class TweetSpout extends BaseRichSpout { // Twitter API authentication credentials String custkey, custsecret; String accesstoken, accesssecret; // To output tuples from spout to the next stage bolt SpoutOutputCollector collector; // Twitter4j - twitter stream to get tweets TwitterStream twitterStream; // Shared queue for getting buffering tweets received LinkedBlockingQueue<String> queue = null; // Class for listening on the tweet stream - for twitter4j private class TweetListener implements StatusListener { // Implement the callback function when a tweet arrives @Override public void onStatus(Status status) { // add the tweet into the queue buffer queue.offer(status.getText()); } @Override public void onDeletionNotice(StatusDeletionNotice sdn) { } @Override public void onTrackLimitationNotice(int i) { } @Override public void onScrubGeo(long l, long l1) { } @Override public void onStallWarning(StallWarning warning) { } @Override public void onException(Exception e) { e.printStackTrace(); } }; /** * Constructor for tweet spout that accepts the credentials */ public TweetSpout( String key, String secret, String token, String tokensecret) { custkey = key; custsecret = secret; accesstoken = token; accesssecret = tokensecret; } @Override public void open( Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) { // create the buffer to block tweets queue = new LinkedBlockingQueue<String>(1000); // save the output collector for emitting tuples collector = spoutOutputCollector; // build the config with credentials for twitter 4j ConfigurationBuilder config = new ConfigurationBuilder() .setOAuthConsumerKey(custkey) .setOAuthConsumerSecret(custsecret) .setOAuthAccessToken(accesstoken) .setOAuthAccessTokenSecret(accesssecret); // create the twitter stream factory with the config TwitterStreamFactory fact = new TwitterStreamFactory(config.build()); // get an instance of twitter stream twitterStream = fact.getInstance(); // provide the handler for twitter stream twitterStream.addListener(new TweetListener()); // start the sampling of tweets twitterStream.sample(); } @Override public void nextTuple() { // try to pick a tweet from the buffer String ret = queue.poll(); // if no tweet is available, wait for 50 ms and return if (ret==null) { Utils.sleep(50); return; } // now emit the tweet to next stage bolt collector.emit(new Values(ret)); } @Override public void close() { // shutdown the stream - when we are going to exit twitterStream.shutdown(); } /** * Component specific configuration */ @Override public Map<String, Object> getComponentConfiguration() { // create the component config Config ret = new Config(); // set the parallelism for this spout to be 1 ret.setMaxTaskParallelism(1); return ret; } @Override public void declareOutputFields( OutputFieldsDeclarer outputFieldsDeclarer) { // tell storm the schema of the output tuple for this spout // tuple consists of a single column called 'tweet' outputFieldsDeclarer.declare(new Fields("tweet")); } }