package storm.applications.spout; import backtype.storm.tuple.Values; import backtype.storm.utils.Utils; import java.util.concurrent.LinkedBlockingQueue; import org.apache.log4j.Logger; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import storm.applications.constants.BaseConstants.BaseConf; import twitter4j.*; import twitter4j.conf.ConfigurationBuilder; import twitter4j.json.DataObjectFactory; /** * Spout which gets tweets from Twitter using OAuth Credentials. * https://github.com/voltas/real-time-sentiment-analytic * * @author Saurabh Dubey <147am@gmail.com> */ public class TwitterStreamingSpout extends AbstractSpout { private static final Logger LOG = Logger.getLogger(TwitterStreamingSpout.class); private static final JSONParser jsonParser = new JSONParser(); private LinkedBlockingQueue<JSONObject> queue; private TwitterStream twitterStream; private FilterQuery filterQuery; @Override public void initialize() { this.queue = new LinkedBlockingQueue<>(1000); StatusListener statusListener = new TwitterStatusListener(queue); // Twitter stream authentication setup ConfigurationBuilder cfgBuilder = new ConfigurationBuilder(); cfgBuilder.setIncludeEntitiesEnabled(true); cfgBuilder.setJSONStoreEnabled(true); cfgBuilder.setOAuthAccessToken(config.getString(getConfigKey(BaseConf.TWITTER_ACCESS_TOKEN))); cfgBuilder.setOAuthAccessTokenSecret(config.getString(getConfigKey(BaseConf.TWITTER_ACCESS_TOKEN_SECRET))); cfgBuilder.setOAuthConsumerKey(config.getString(getConfigKey(BaseConf.TWITTER_CONSUMER_KEY))); cfgBuilder.setOAuthConsumerSecret(config.getString(getConfigKey(BaseConf.TWITTER_CONSUMER_SECRET))); twitterStream = new TwitterStreamFactory(cfgBuilder.build()).getInstance(); twitterStream.addListener(statusListener); if (filterQuery != null) { twitterStream.filter(filterQuery); } else { twitterStream.sample(); } } @Override public void nextTuple() { JSONObject status = queue.poll(); if (null == status) { //If _queue is empty sleep the spout thread so it doesn't consume resources. Utils.sleep(500); } else { //Emit the complete tweet to the Bolt. collector.emit(new Values(status)); } } @Override public void close() { twitterStream.cleanUp(); twitterStream.shutdown(); } public void setFilterQuery(FilterQuery filterQuery) { this.filterQuery = filterQuery; } private static class TwitterStatusListener implements StatusListener { private LinkedBlockingQueue<JSONObject> queue; public TwitterStatusListener(LinkedBlockingQueue<JSONObject> queue) { this.queue = queue; } @Override public void onStatus(final Status status) { try { String jsonStr = DataObjectFactory.getRawJSON(status); queue.offer((JSONObject) jsonParser.parse(jsonStr)); } catch (ParseException ex) { LOG.error("Error parsing JSON encoded tweet", ex); } } @Override public void onDeletionNotice(final StatusDeletionNotice sdn) { } @Override public void onTrackLimitationNotice(final int i) { } @Override public void onScrubGeo(final long l, final long l1) { } @Override public void onStallWarning(final StallWarning stallWarning) { } @Override public void onException(final Exception e) { } } }