package org.calrissian.flowbox.bolt;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import org.calrissian.flowbox.FlowboxFactory;
import org.calrissian.flowbox.model.EachOp;
import org.calrissian.flowbox.model.Event;
import org.calrissian.flowbox.model.Flow;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.calrissian.flowbox.Constants.*;
import static org.calrissian.flowbox.spout.MockFlowLoaderSpout.FLOW_LOADER_STREAM;
/**
* A each allows an event to be processed, mutated, split, or transformed.
*/
public class EachBolt extends BaseRichBolt {
Map<String,Flow> flows;
OutputCollector collector;
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.collector = outputCollector;
flows = new HashMap<String, Flow>();
}
@Override
public void execute(Tuple tuple) {
if(FLOW_LOADER_STREAM.equals(tuple.getSourceStreamId())) {
for(Flow flow : (Collection<Flow>)tuple.getValue(0))
flows.put(flow.getId(), flow);
} else if(!"tick".equals(tuple.getSourceStreamId())){
String flowId = tuple.getStringByField(FLOW_ID);
Event event = (Event) tuple.getValueByField(EVENT);
int idx = tuple.getIntegerByField(FLOW_OP_IDX);
idx++;
String streamName = tuple.getStringByField(STREAM_NAME);
String previousStream = tuple.getStringByField(LAST_STREAM);
Flow flow = flows.get(flowId);
if(flow != null) {
EachOp functionOp = (EachOp) flow.getStream(streamName).getFlowOps().get(idx);
String nextStream = idx+1 < flow.getStream(streamName).getFlowOps().size() ? flow.getStream(streamName).getFlowOps().get(idx + 1).getComponentName() : "output";
List<Event> events = functionOp.getFunction().execute(event);
if((nextStream.equals("output") && flow.getStream(streamName).isStdOutput()) || !nextStream.equals("output")) {
if(events != null) {
for (Event newEvent : events)
collector.emit(nextStream, tuple, new Values(flowId, newEvent, idx, streamName, previousStream));
// send directly to any non std output streams that may be configured
if (nextStream.equals("output") && flow.getStream(streamName).getOutputs() != null) {
for (String output : flow.getStream(streamName).getOutputs()) {
if (events != null) {
for (Event newEvent : events) {
String outputStream = flow.getStream(output).getFlowOps().get(0).getComponentName();
collector.emit(outputStream, tuple, new Values(flowId, newEvent, -1, output, streamName));
}
}
}
}
}
}
}
}
collector.ack(tuple);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
FlowboxFactory.declareOutputStreams(outputFieldsDeclarer);
}
}