├── .gitignore
├── src
└── main
│ ├── resources
│ └── words.txt
│ └── java
│ ├── countword
│ ├── spouts
│ │ ├── SignalsSpout.java
│ │ └── WordReader.java
│ ├── TopologyMain.java
│ └── bolts
│ │ ├── WordNormalizer.java
│ │ └── WordCounter.java
│ └── drpc
│ ├── AdderBolt.java
│ └── DRPCTopologyMain.java
├── .settings
├── org.eclipse.jdt.core.prefs
└── org.maven.ide.eclipse.prefs
├── .project
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.classpath
3 |
--------------------------------------------------------------------------------
/src/main/resources/words.txt:
--------------------------------------------------------------------------------
1 | storm
2 | test
3 | are
4 | great
5 | is
6 | an
7 | storm
8 | simple
9 | application
10 | but
11 | very
12 | powerfull
13 | really
14 | StOrm
15 | is
16 | great
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Sun Apr 22 00:24:03 ART 2012
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.compliance=1.6
5 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
6 | org.eclipse.jdt.core.compiler.source=1.6
7 |
--------------------------------------------------------------------------------
/.settings/org.maven.ide.eclipse.prefs:
--------------------------------------------------------------------------------
1 | #Wed Feb 01 00:58:33 ART 2012
2 | activeProfiles=
3 | eclipse.preferences.version=1
4 | fullBuildGoals=process-test-resources
5 | includeModules=false
6 | resolveWorkspaceProjects=true
7 | resourceFilterGoals=process-resources resources\:testResources
8 | skipCompilerPlugin=true
9 | version=1
10 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ch03-topologies
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.maven.ide.eclipse.maven2Builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.maven.ide.eclipse.maven2Nature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/countword/spouts/SignalsSpout.java:
--------------------------------------------------------------------------------
1 | package countword.spouts;
2 |
3 | import java.util.Map;
4 |
5 | import backtype.storm.spout.SpoutOutputCollector;
6 | import backtype.storm.task.TopologyContext;
7 | import backtype.storm.topology.OutputFieldsDeclarer;
8 | import backtype.storm.topology.base.BaseRichSpout;
9 | import backtype.storm.tuple.Fields;
10 | import backtype.storm.tuple.Values;
11 |
12 | public class SignalsSpout extends BaseRichSpout{
13 |
14 | private SpoutOutputCollector collector;
15 |
16 |
17 | @Override
18 | public void nextTuple() {
19 | collector.emit("signals",new Values("refreshCache"));
20 | try {
21 | Thread.sleep(1000);
22 | } catch (InterruptedException e) {}
23 | }
24 |
25 | @Override
26 | public void open(Map conf, TopologyContext context,
27 | SpoutOutputCollector collector) {
28 | this.collector = collector;
29 | }
30 |
31 | @Override
32 | public void declareOutputFields(OutputFieldsDeclarer declarer) {
33 | declarer.declareStream("signals",new Fields("action"));
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | storm.book
4 | Topologies
5 | 0.0.1-SNAPSHOT
6 |
7 |
8 |
9 |
10 | org.apache.maven.plugins
11 | maven-compiler-plugin
12 | 2.3.2
13 |
14 | 1.6
15 | 1.6
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | clojars.org
26 | http://clojars.org/repo
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | storm
36 | storm
37 | 0.7.1
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/main/java/countword/TopologyMain.java:
--------------------------------------------------------------------------------
1 | package countword;
2 |
3 | import countword.spouts.SignalsSpout;
4 | import countword.spouts.WordReader;
5 | import countword.bolts.WordCounter;
6 | import countword.bolts.WordNormalizer;
7 | import backtype.storm.Config;
8 | import backtype.storm.LocalCluster;
9 | import backtype.storm.topology.TopologyBuilder;
10 | import backtype.storm.tuple.Fields;
11 |
12 |
13 | public class TopologyMain {
14 | public static void main(String[] args) throws InterruptedException {
15 |
16 | //Topology definition
17 | TopologyBuilder builder = new TopologyBuilder();
18 | builder.setSpout("word-reader",new WordReader());
19 | builder.setSpout("signals-spout",new SignalsSpout());
20 | builder.setBolt("word-normalizer", new WordNormalizer())
21 | .shuffleGrouping("word-reader");
22 |
23 | builder.setBolt("word-counter", new WordCounter(),2)
24 | .fieldsGrouping("word-normalizer",new Fields("word"))
25 | .allGrouping("signals-spout","signals");
26 |
27 |
28 | //Configuration
29 | Config conf = new Config();
30 | conf.put("wordsFile", args[0]);
31 | conf.setDebug(true);
32 | //Topology run
33 | conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 1);
34 | LocalCluster cluster = new LocalCluster();
35 | cluster.submitTopology("Count-Word-Toplogy-With-Refresh-Cache", conf, builder.createTopology());
36 | Thread.sleep(5000);
37 | cluster.shutdown();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/drpc/AdderBolt.java:
--------------------------------------------------------------------------------
1 | package drpc;
2 |
3 | import java.security.InvalidParameterException;
4 | import java.util.Map;
5 |
6 | import backtype.storm.task.OutputCollector;
7 | import backtype.storm.task.TopologyContext;
8 | import backtype.storm.topology.BasicOutputCollector;
9 | import backtype.storm.topology.IRichBolt;
10 | import backtype.storm.topology.OutputFieldsDeclarer;
11 | import backtype.storm.topology.base.BaseBasicBolt;
12 | import backtype.storm.topology.base.BaseRichBolt;
13 | import backtype.storm.tuple.Fields;
14 | import backtype.storm.tuple.Tuple;
15 | import backtype.storm.tuple.Values;
16 |
17 | public class AdderBolt extends BaseBasicBolt{
18 |
19 | private static final Object NULL = "NULL";
20 | private OutputCollector collector;
21 |
22 | @Override
23 | public void execute(Tuple input, BasicOutputCollector collector) {
24 | //Parse the add expression
25 | String[] numbers = (String[]) input.getString(1).split("\\+");
26 | Integer added = 0;
27 | try{
28 | if(numbers.length<2){
29 | throw new InvalidParameterException("Should be at least 2 numbers");
30 | }
31 | for(String num : numbers){
32 | //Add each member
33 | added += Integer.parseInt((java.lang.String) num);
34 | }
35 | }catch(Exception e){
36 | //On error emit null
37 | collector.emit(new Values(input.getValue(0),NULL));
38 | }
39 | //Emit the result
40 | collector.emit(new Values(input.getValue(0),added));
41 | }
42 |
43 | @Override
44 | public void declareOutputFields(OutputFieldsDeclarer declarer) {
45 | declarer.declare(new Fields("id","result"));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/drpc/DRPCTopologyMain.java:
--------------------------------------------------------------------------------
1 | package drpc;
2 |
3 | import backtype.storm.Config;
4 | import backtype.storm.LocalCluster;
5 | import backtype.storm.LocalDRPC;
6 | import backtype.storm.drpc.LinearDRPCTopologyBuilder;
7 | import backtype.storm.utils.DRPCClient;
8 |
9 | /**
10 | * DRPC example
11 | *
12 | * @author Storm-Book
13 | *
14 | */
15 | public class DRPCTopologyMain {
16 |
17 | public static void main(String[] args) {
18 | //Create the local drpc client/server
19 | LocalDRPC drpc = new LocalDRPC();
20 |
21 | //Create the drpc topology
22 | LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("add");
23 | builder.addBolt(new AdderBolt(),2);
24 |
25 | Config conf = new Config();
26 | conf.setDebug(true);
27 |
28 | //Create cluster and submit the topology
29 | LocalCluster cluster = new LocalCluster();
30 | cluster.submitTopology("drpc-adder-topology", conf, builder.createLocalTopology(drpc));
31 |
32 | //Test the topology
33 | String result = drpc.execute("add", "1+-1");
34 | checkResult(result,0);
35 | result = drpc.execute("add", "1+1+5+10");
36 |
37 | //Finish and shutdown
38 | checkResult(result,17);
39 | cluster.shutdown();
40 | drpc.shutdown();
41 | }
42 |
43 | private static boolean checkResult(String result, int expected) {
44 | if(result != null && !result.equals("NULL")){
45 | if(Integer.parseInt(result) == expected){
46 | System.out.println("Add valid [result: "+result+"]");
47 | return true;
48 | }else{
49 | System.err.print("Invalid result ["+result+"]");
50 | }
51 | }else{
52 | System.err.println("There was an error running the drpc call");
53 | }
54 | return false;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/countword/bolts/WordNormalizer.java:
--------------------------------------------------------------------------------
1 | package countword.bolts;
2 |
3 | import java.util.Map;
4 |
5 | import backtype.storm.task.OutputCollector;
6 | import backtype.storm.task.TopologyContext;
7 | import backtype.storm.topology.OutputFieldsDeclarer;
8 | import backtype.storm.topology.base.BaseRichBolt;
9 | import backtype.storm.tuple.Fields;
10 | import backtype.storm.tuple.Tuple;
11 | import backtype.storm.tuple.Values;
12 |
13 | public class WordNormalizer extends BaseRichBolt {
14 |
15 | private OutputCollector collector;
16 | int numCounterTasks=0;
17 | public void cleanup() {}
18 |
19 | /**
20 | * The bolt will receive the line from the
21 | * words file and process it to Normalize this line
22 | *
23 | * The normalize will be put the words in lower case
24 | * and split the line to get all words in this
25 | */
26 | public void execute(Tuple input) {
27 | String sentence = input.getString(0);
28 | String[] words = sentence.split(" ");
29 | for(String word : words){
30 | word = word.trim();
31 | if(!word.isEmpty()){
32 | word = word.toLowerCase();
33 | collector.emit(new Values(word));
34 | }
35 | }
36 | // Acknowledge the tuple
37 | collector.ack(input);
38 | }
39 | public void prepare(Map stormConf, TopologyContext context,
40 | OutputCollector collector) {
41 | this.collector = collector;
42 | this.numCounterTasks = context.getComponentTasks("word-counter").size();
43 | }
44 |
45 | /**
46 | * The bolt will only emit the field "word"
47 | */
48 | public void declareOutputFields(OutputFieldsDeclarer declarer) {
49 | declarer.declare(new Fields("word"));
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/countword/bolts/WordCounter.java:
--------------------------------------------------------------------------------
1 | package countword.bolts;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import backtype.storm.task.OutputCollector;
7 | import backtype.storm.task.TopologyContext;
8 | import backtype.storm.topology.OutputFieldsDeclarer;
9 | import backtype.storm.topology.base.BaseRichBolt;
10 | import backtype.storm.tuple.Tuple;
11 |
12 | public class WordCounter extends BaseRichBolt {
13 |
14 | Integer id;
15 | String name;
16 | Map counters;
17 | private OutputCollector collector;
18 |
19 | /**
20 | * At the end of the spout (when the cluster is shutdown
21 | * We will show the word counters
22 | */
23 | @Override
24 | public void cleanup() {
25 | System.out.println("-- Word Counter ["+name+"-"+id+"] --");
26 | for(Map.Entry entry : counters.entrySet()){
27 | System.out.println(entry.getKey()+": "+entry.getValue());
28 | }
29 | }
30 |
31 | /**
32 | * On each word We will count
33 | */
34 | @Override
35 | public void execute(Tuple input) {
36 | String str = null;
37 | try{
38 | str = input.getStringByField("word");
39 | }catch (IllegalArgumentException e) {
40 | //Do nothing
41 | }
42 |
43 | if(str!=null){
44 | /**
45 | * If the word dosn't exist in the map we will create
46 | * this, if not We will add 1
47 | */
48 | if(!counters.containsKey(str)){
49 | counters.put(str, 1);
50 | }else{
51 | Integer c = counters.get(str) + 1;
52 | counters.put(str, c);
53 | }
54 | }else{
55 | if(input.getSourceStreamId().equals("signals")){
56 | str = input.getStringByField("action");
57 | if("refreshCache".equals(str))
58 | counters.clear();
59 | }
60 | }
61 | //Set the tuple as Acknowledge
62 | collector.ack(input);
63 | }
64 |
65 | /**
66 | * On create
67 | */
68 | @Override
69 | public void prepare(Map stormConf, TopologyContext context,
70 | OutputCollector collector) {
71 | this.counters = new HashMap();
72 | this.collector = collector;
73 | this.name = context.getThisComponentId();
74 | this.id = context.getThisTaskId();
75 | }
76 |
77 | @Override
78 | public void declareOutputFields(OutputFieldsDeclarer declarer) {}
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/countword/spouts/WordReader.java:
--------------------------------------------------------------------------------
1 | package countword.spouts;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.FileNotFoundException;
5 | import java.io.FileReader;
6 | import java.util.Map;
7 | import backtype.storm.spout.SpoutOutputCollector;
8 | import backtype.storm.task.TopologyContext;
9 | import backtype.storm.topology.IRichSpout;
10 | import backtype.storm.topology.OutputFieldsDeclarer;
11 | import backtype.storm.topology.base.BaseRichSpout;
12 | import backtype.storm.tuple.Fields;
13 | import backtype.storm.tuple.Values;
14 |
15 | public class WordReader extends BaseRichSpout {
16 |
17 | private SpoutOutputCollector collector;
18 | private FileReader fileReader;
19 | private boolean completed = false;
20 | private TopologyContext context;
21 |
22 | public void ack(Object msgId) {
23 | System.out.println("OK:"+msgId);
24 | }
25 | public void close() {}
26 | public void fail(Object msgId) {
27 | System.out.println("FAIL:"+msgId);
28 | }
29 |
30 | /**
31 | * The only thing that the methods will do It is emit each
32 | * file line
33 | */
34 | public void nextTuple() {
35 | /**
36 | * The nextuple it is called forever, so if we have been readed the file
37 | * we will wait and then return
38 | */
39 | if(completed){
40 | try {
41 | Thread.sleep(1000);
42 | } catch (InterruptedException e) {
43 | //Do nothing
44 | }
45 | return;
46 | }
47 | String str;
48 | //Open the reader
49 | BufferedReader reader = new BufferedReader(fileReader);
50 | try{
51 | //Read all lines
52 | while((str = reader.readLine()) != null){
53 | /**
54 | * By each line emmit a new value with the line as a their
55 | */
56 | this.collector.emit(new Values(str),str);
57 | }
58 | }catch(Exception e){
59 | throw new RuntimeException("Error reading tuple",e);
60 | }finally{
61 | completed = true;
62 | }
63 | }
64 |
65 | /**
66 | * We will create the file and get the collector object
67 | */
68 | public void open(Map conf, TopologyContext context,
69 | SpoutOutputCollector collector) {
70 | try {
71 | this.context = context;
72 | this.fileReader = new FileReader(conf.get("wordsFile").toString());
73 | } catch (FileNotFoundException e) {
74 | throw new RuntimeException("Error reading file ["+conf.get("wordFile")+"]");
75 | }
76 | this.collector = collector;
77 | }
78 |
79 | /**
80 | * Declare the output field "word"
81 | */
82 | public void declareOutputFields(OutputFieldsDeclarer declarer) {
83 | declarer.declare(new Fields("line"));
84 | }
85 | }
86 |
--------------------------------------------------------------------------------