package twitter.streaming; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.log4j.Logger; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import backtype.storm.spout.SpoutOutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.topology.base.BaseRichSpout; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Values; public class ApiStreamingSpout extends BaseRichSpout implements Runnable{ static String STREAMING_API_URL="https://stream.twitter.com/1/statuses/filter.json?track="; private String track; private String user; private String password; private DefaultHttpClient client; private SpoutOutputCollector collector; private UsernamePasswordCredentials credentials; private BasicCredentialsProvider credentialProvider; static Logger LOG = Logger.getLogger(ApiStreamingSpout.class); LinkedBlockingQueue<String> tweets = new LinkedBlockingQueue<String>(); @Override public void nextTuple() { if(tweets.size()>0){ Collection<Object> tweetsToEmit = new ArrayList<Object>(); tweets.drainTo(tweetsToEmit); for(Object tweet : tweetsToEmit){ collector.emit(new Values(track,tweet)); } } } @Override public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) { int spoutsSize = context.getComponentTasks(context.getThisComponentId()).size(); int myIdx = context.getThisTaskIndex(); String[] tracks = ((String) conf.get("track")).split(","); StringBuffer tracksBuffer = new StringBuffer(); for(int i=0; i< tracks.length;i++){ if( i % spoutsSize == myIdx){ tracksBuffer.append(","); tracksBuffer.append(tracks[i]); } } if(tracksBuffer.length() == 0) throw new RuntimeException("No track found for spout" + " [spoutsSize:"+spoutsSize+", tracks:"+tracks.length+"] the amount" + " of tracks must be more then the spout paralellism"); this.track =tracksBuffer.substring(1).toString(); user = (String) conf.get("user"); password = (String) conf.get("password"); credentials = new UsernamePasswordCredentials(user, password); credentialProvider = new BasicCredentialsProvider(); credentialProvider.setCredentials(AuthScope.ANY, credentials); this.collector = collector; new Thread(this).start(); } @Override public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declare(new Fields("criteria","tweet")); } @Override public void run() { /* * Create the client call */ while(true){ try{ client = new DefaultHttpClient(); client.setCredentialsProvider(credentialProvider); HttpGet get = new HttpGet(STREAMING_API_URL+track); HttpResponse response; try { //Execute response = client.execute(get); StatusLine status = response.getStatusLine(); if(status.getStatusCode() == 200){ InputStream inputStream = response.getEntity().getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String in; //Read line by line while((in = reader.readLine())!=null){ //Parse and emit tweets.add(in); } } } catch (IOException e) { LOG.error("Error in communication with twitter api ["+get.getURI().toString()+"]"); try { Thread.sleep(10000); } catch (InterruptedException e1) { } } }catch(Throwable e){ LOG.error(e); } LOG.error("An error ocurs, all runnable thread will be restarted"); try{ Thread.sleep(1000); }catch(Exception e){ } } } }