package bharati.binita.storm.trident.eg7;

import storm.trident.Stream;
import storm.trident.TridentTopology;
import storm.trident.operation.builtin.Count;
import backtype.storm.Config;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.generated.StormTopology;
import backtype.storm.tuple.Fields;

/**
 * 
 * @author [email protected]
 * http://metabroadcast.com/blog/testing-storm
 * https://storm.incubator.apache.org/documentation/Trident-state
 * http://svendvanderveken.wordpress.com/2014/02/05/error-handling-in-storm-trident-topologies/
 * http://metabroadcast.com/blog/testing-storm
 * https://blog.twitter.com/2012/trident-a-high-level-abstraction-for-realtime-computation
 * 
 *  Illustrates the following:
 *  - Demo of Opaque transactional State. (Refer to Opaque transactional spout here : https://storm.incubator.apache.org/documentation/Trident-state)
 *  - State API usage, using storm.trident.state.map.MapState API. This example shows use of OpaqueMap MapState type.
 *  - Persistence of State, using storm.trident.state.map.IBackingMap API. 
 *      (In Trident, State can not be called as a 'State' without effective persistence. Redis is used as for underlying storage.) 
 *
 */

public class ExampleTopology {
	
	public static StormTopology buildTopology()
	
	{
		TridentTopology topology = new TridentTopology();
		RandomPhraseSpout spout1 = new RandomPhraseSpout();
		
		Stream inputStream = topology.newStream("dumbo", spout1);//where is dump used ? No where as per as I see.
		
		/**
		 * persistentAggregate : The persistentAggregate operation updates a source of state.
		 * persistentAggregate is an additional abstraction built on top of partitionPersist that knows how to take a 
		 * Trident aggregator and use it to apply updates to the source of state.
		 * Args:
		 * StateFactory instance - This factory implement the makeState API, that should return a instance of State.
		 * Fields list, that needs to be persisted. These field list should be present in the input stream.
		 * StateUpdater instance - The StateUpdater instance will update the underlying State.
		 */
		 inputStream
		    //input stream generated by spout1 has a field called randomPhrase.
		    //RandomPhraseSplitter takes a randomPhrase and additionally emits a field called randomWord into the stream.
		    .each(new Fields("randomPhrase"), new RandomPhraseSplitter(), new Fields("randomWord"))
		    //the input stream is grouped by randomWord - Isn't this same as storm field grouping ? yes , similar.
		    .groupBy(new Fields("randomWord"))
		    //count the occurence of randomWord using Count aggregrator, that will add a field called count to the stream.
		    //persist the count in Redis.
		    .persistentAggregate(new RedisStoreStateFactory(), new Count(), new Fields("count"));
		 
		 return topology.build();
	}

	public static void main(String[] args) throws Exception {
		
		Config conf = new Config();
		conf.put("redisServerIP", args[0]);
		conf.put("redisServerPort", args[1]);
		conf.put("phraseCount", "4");

		StormSubmitter.submitTopology("trident-eg7", conf,
        		buildTopology());
	
	}

}