package backtype.storm.clojure; import backtype.storm.coordination.CoordinatedBolt.FinishedCallback; import backtype.storm.generated.StreamInfo; import backtype.storm.task.IBolt; import backtype.storm.task.OutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.topology.IRichBolt; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.utils.Utils; import clojure.lang.IFn; import clojure.lang.PersistentArrayMap; import clojure.lang.Keyword; import clojure.lang.Symbol; import clojure.lang.RT; import java.util.ArrayList; import java.util.List; import java.util.Map; public class ClojureBolt implements IRichBolt, FinishedCallback { Map<String, StreamInfo> _fields; List<String> _fnSpec; List<String> _confSpec; List<Object> _params; IBolt _bolt; public ClojureBolt(List fnSpec, List confSpec, List<Object> params, Map<String, StreamInfo> fields) { _fnSpec = fnSpec; _confSpec = confSpec; _params = params; _fields = fields; } @Override public void prepare(final Map stormConf, final TopologyContext context, final OutputCollector collector) { IFn hof = Utils.loadClojureFn(_fnSpec.get(0), _fnSpec.get(1)); try { IFn preparer = (IFn) hof.applyTo(RT.seq(_params)); final Map<Keyword,Object> collectorMap = new PersistentArrayMap( new Object[] { Keyword.intern(Symbol.create("output-collector")), collector, Keyword.intern(Symbol.create("context")), context}); List<Object> args = new ArrayList<Object>() {{ add(stormConf); add(context); add(collectorMap); }}; _bolt = (IBolt) preparer.applyTo(RT.seq(args)); //this is kind of unnecessary for clojure try { _bolt.prepare(stormConf, context, collector); } catch(AbstractMethodError ame) { } } catch (Exception e) { throw new RuntimeException(e); } } @Override public void execute(Tuple input) { _bolt.execute(input); } @Override public void cleanup() { try { _bolt.cleanup(); } catch(AbstractMethodError ame) { } } @Override public void declareOutputFields(OutputFieldsDeclarer declarer) { for(String stream: _fields.keySet()) { StreamInfo info = _fields.get(stream); declarer.declareStream(stream, info.is_direct(), new Fields(info.get_output_fields())); } } @Override public void finishedId(Object id) { if(_bolt instanceof FinishedCallback) { ((FinishedCallback) _bolt).finishedId(id); } } @Override public Map<String, Object> getComponentConfiguration() { IFn hof = Utils.loadClojureFn(_confSpec.get(0), _confSpec.get(1)); try { return (Map) hof.applyTo(RT.seq(_params)); } catch (Exception e) { throw new RuntimeException(e); } } }