redstorm 0.6.6 → 0.7.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6 -1
  3. data/README.md +8 -7
  4. data/examples/dsl/exclamation_topology.rb +2 -4
  5. data/examples/dsl/exclamation_topology2.rb +4 -5
  6. data/examples/dsl/hello_world_topology.rb +7 -0
  7. data/examples/dsl/kafka_topology.rb +5 -1
  8. data/examples/dsl/redis_word_count_topology.rb +5 -9
  9. data/examples/dsl/ruby_version_topology.rb +2 -0
  10. data/examples/dsl/word_count_topology.rb +4 -5
  11. data/examples/trident/word_count_query.rb +33 -0
  12. data/examples/trident/word_count_topology.rb +153 -0
  13. data/ivy/storm_dependencies.xml +1 -1
  14. data/ivy/topology_dependencies.xml +3 -2
  15. data/lib/red_storm.rb +5 -2
  16. data/lib/red_storm/configurator.rb +12 -0
  17. data/lib/red_storm/dsl/batch_bolt.rb +34 -0
  18. data/lib/red_storm/dsl/batch_committer_bolt.rb +9 -0
  19. data/lib/red_storm/dsl/batch_spout.rb +53 -0
  20. data/lib/red_storm/dsl/bolt.rb +7 -2
  21. data/lib/red_storm/dsl/output_collector.rb +8 -0
  22. data/lib/red_storm/dsl/spout.rb +3 -1
  23. data/lib/red_storm/dsl/topology.rb +2 -2
  24. data/lib/red_storm/dsl/tuple.rb +2 -0
  25. data/lib/red_storm/topology_launcher.rb +14 -10
  26. data/lib/red_storm/version.rb +1 -1
  27. data/redstorm.gemspec +1 -0
  28. data/src/main/redstorm/storm/jruby/JRubyBatchBolt.java +53 -35
  29. data/src/main/redstorm/storm/jruby/JRubyBatchSpout.java +77 -42
  30. data/src/main/redstorm/storm/jruby/JRubyBolt.java +54 -34
  31. data/src/main/redstorm/storm/jruby/JRubySpout.java +62 -40
  32. data/src/main/redstorm/storm/jruby/JRubyTransactionalBolt.java +57 -35
  33. data/src/main/redstorm/storm/jruby/JRubyTransactionalCommitterBolt.java +6 -17
  34. data/src/main/redstorm/storm/jruby/JRubyTransactionalCommitterSpout.java +14 -26
  35. data/src/main/redstorm/storm/jruby/JRubyTransactionalSpout.java +60 -37
  36. data/src/main/redstorm/storm/jruby/JRubyTridentFunction.java +66 -0
  37. metadata +16 -23
  38. data/lib/red_storm/proxy/batch_bolt.rb +0 -63
  39. data/lib/red_storm/proxy/batch_committer_bolt.rb +0 -52
  40. data/lib/red_storm/proxy/batch_spout.rb +0 -59
  41. data/lib/red_storm/proxy/bolt.rb +0 -63
  42. data/lib/red_storm/proxy/proxy_function.rb +0 -40
  43. data/lib/red_storm/proxy/spout.rb +0 -87
  44. data/lib/red_storm/proxy/transactional_committer_spout.rb +0 -47
  45. data/lib/red_storm/proxy/transactional_spout.rb +0 -46
  46. data/src/main/redstorm/storm/jruby/JRubyProxyFunction.java +0 -51
@@ -0,0 +1,9 @@
1
+ module RedStorm
2
+ module DSL
3
+
4
+ class BatchCommitterBolt < BatchBolt
5
+
6
+ def self.java_proxy; "Java::RedstormStormJruby::JRubyBatchCommitterBolt"; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ module RedStorm
2
+ module DSL
3
+
4
+ class BatchSpout < Spout
5
+
6
+ def self.java_proxy; "Java::RedstormStormJruby::JRubyBatchSpout"; end
7
+
8
+ def get_output_fields
9
+ Fields.new(self.class.fields)
10
+ end
11
+
12
+ def self.on_emit_batch(*args, &on_emit_batch_block)
13
+ options = args.last.is_a?(Hash) ? args.pop : {}
14
+ method_name = args.first
15
+
16
+ self.on_emit_batch_options.merge!(options)
17
+
18
+ # indirecting through a lambda defers the method lookup at invocation time
19
+ # and the performance penalty is negligible
20
+ body = block_given? ? on_emit_batch_block : lambda{|batch_id, collector| self.send((method_name || :on_emit_batch).to_sym)}
21
+ define_method(:on_emit_batch, body)
22
+ end
23
+
24
+ # Spout proxy interface
25
+
26
+ #
27
+ # note that in batch spout, ack is for the batch id and not the message id as in the base spout.
28
+ # TODO maybe rename msg_id to just id in the base spout
29
+ #
30
+
31
+ def emit_batch(batch_id, collector)
32
+ # TODO this is a TridentCollector, emit should just work by setting @collector
33
+ # report_error need to be hooked?
34
+ @collector = collector
35
+ on_emit_batch(batch_id, collector)
36
+ end
37
+
38
+ def open(config, context)
39
+ @context = context
40
+ @config = config
41
+
42
+ on_init
43
+ end
44
+
45
+ private
46
+
47
+ def self.on_emit_batch_options
48
+ @on_emit_batch_options ||= {}
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -3,6 +3,9 @@ require 'red_storm/configurator'
3
3
  require 'red_storm/environment'
4
4
  require 'pathname'
5
5
 
6
+ java_import 'backtype.storm.tuple.Fields'
7
+ java_import 'backtype.storm.tuple.Values'
8
+
6
9
  module RedStorm
7
10
  module DSL
8
11
 
@@ -11,6 +14,8 @@ module RedStorm
11
14
  class Bolt
12
15
  attr_reader :collector, :context, :config
13
16
 
17
+ def self.java_proxy; "Java::RedstormStormJruby::JRubyBolt"; end
18
+
14
19
  # DSL class methods
15
20
 
16
21
  def self.log
@@ -54,11 +59,11 @@ module RedStorm
54
59
  end
55
60
 
56
61
  def unanchored_emit(*values)
57
- @collector.emit(Values.new(*values))
62
+ @collector.emit_tuple(Values.new(*values))
58
63
  end
59
64
 
60
65
  def anchored_emit(tuple, *values)
61
- @collector.emit(tuple, Values.new(*values))
66
+ @collector.emit_anchor_tuple(tuple, Values.new(*values))
62
67
  end
63
68
 
64
69
  def ack(tuple)
@@ -0,0 +1,8 @@
1
+ require 'java'
2
+ java_import 'backtype.storm.task.OutputCollector'
3
+
4
+ # make alias methods to specific signatures to avoid selection overhead for heavily overloaded method
5
+ class OutputCollector
6
+ java_alias :emit_tuple, :emit, [java.lang.Class.for_name("java.util.List")]
7
+ java_alias :emit_anchor_tuple, :emit, [java.lang.Class.for_name("backtype.storm.tuple.Tuple"), java.lang.Class.for_name("java.util.List")]
8
+ end
@@ -11,6 +11,8 @@ module RedStorm
11
11
  class Spout
12
12
  attr_reader :config, :context, :collector
13
13
 
14
+ def self.java_proxy; "Java::RedstormStormJruby::JRubySpout"; end
15
+
14
16
  # DSL class methods
15
17
 
16
18
  def self.configure(&configure_block)
@@ -99,7 +101,7 @@ module RedStorm
99
101
  unreliable_emit(*values)
100
102
  end
101
103
  else
102
- sleep(0.1)
104
+ sleep(0.1) # see https://twitter.com/colinsurprenant/status/406445541904494592
103
105
  end
104
106
  end
105
107
  end
@@ -46,7 +46,7 @@ module RedStorm
46
46
  elsif is_java?
47
47
  @clazz.new(*constructor_args)
48
48
  else
49
- JRubySpout.new(@clazz.base_class_path, @clazz.name, @output_fields)
49
+ Object.module_eval(@clazz.java_proxy).new(@clazz.base_class_path, @clazz.name, @output_fields)
50
50
  end
51
51
  end
52
52
  end
@@ -95,7 +95,7 @@ module RedStorm
95
95
  elsif is_java?
96
96
  @clazz.new(*constructor_args)
97
97
  else
98
- JRubyBolt.new(@clazz.base_class_path, @clazz.name, @output_fields)
98
+ Object.module_eval(@clazz.java_proxy).new(@clazz.base_class_path, @clazz.name, @output_fields)
99
99
  end
100
100
  end
101
101
  end
@@ -23,6 +23,8 @@ class TupleImpl
23
23
  end
24
24
  alias_method :[], :value
25
25
 
26
+ alias_method :values, :getValues # wire directly to avoid method missing indirection
27
+
26
28
  def field_index(field)
27
29
  fieldIndex(field.to_s)
28
30
  end
@@ -2,8 +2,11 @@ require 'java'
2
2
 
3
3
  # This hack get rif of the "Use RbConfig instead of obsolete and deprecated Config"
4
4
  # deprecation warning that is triggered by "java_import 'backtype.storm.Config'".
5
- Object.send :remove_const, :Config
6
- Config = RbConfig
5
+ begin
6
+ Object.send :remove_const, :Config
7
+ Config = RbConfig
8
+ rescue NameError
9
+ end
7
10
 
8
11
  # see https://github.com/colinsurprenant/redstorm/issues/7
9
12
  module Backtype
@@ -20,14 +23,15 @@ java_import 'backtype.storm.tuple.Fields'
20
23
  java_import 'backtype.storm.tuple.Tuple'
21
24
  java_import 'backtype.storm.tuple.Values'
22
25
 
23
- java_import 'redstorm.storm.jruby.JRubyBolt'
24
- java_import 'redstorm.storm.jruby.JRubySpout'
25
- java_import 'redstorm.storm.jruby.JRubyBatchBolt'
26
- java_import 'redstorm.storm.jruby.JRubyBatchCommitterBolt'
27
- java_import 'redstorm.storm.jruby.JRubyBatchSpout'
28
- java_import 'redstorm.storm.jruby.JRubyTransactionalSpout'
29
- java_import 'redstorm.storm.jruby.JRubyTransactionalBolt'
30
- java_import 'redstorm.storm.jruby.JRubyTransactionalCommitterBolt'
26
+ # java_import 'redstorm.storm.jruby.JRubyBolt'
27
+ # java_import 'redstorm.storm.jruby.JRubySpout'
28
+ # java_import 'redstorm.storm.jruby.JRubyBatchBolt'
29
+ # java_import 'redstorm.storm.jruby.JRubyBatchCommitterBolt'
30
+ # java_import 'redstorm.storm.jruby.JRubyBatchSpout'
31
+ # java_import 'redstorm.storm.jruby.JRubyTransactionalSpout'
32
+ # java_import 'redstorm.storm.jruby.JRubyTransactionalBolt'
33
+ # java_import 'redstorm.storm.jruby.JRubyTransactionalCommitterBolt'
34
+ # java_import 'redstorm.storm.jruby.JRubyProxyFunction'
31
35
 
32
36
  java_package 'redstorm'
33
37
 
@@ -1,3 +1,3 @@
1
1
  module RedStorm
2
- VERSION = '0.6.6'
2
+ VERSION = '0.7.0.beta1'
3
3
  end
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.homepage = 'https://github.com/colinsurprenant/redstorm'
12
12
  s.summary = 'JRuby on Storm'
13
13
  s.description = 'JRuby integration & DSL for the Storm distributed realtime computation system'
14
+ s.license = "Apache 2.0"
14
15
 
15
16
  s.rubyforge_project = 'redstorm'
16
17
 
@@ -10,81 +10,99 @@ import backtype.storm.tuple.Tuple;
10
10
  import backtype.storm.tuple.Fields;
11
11
  import java.util.Map;
12
12
 
13
+ import org.jruby.Ruby;
14
+ import org.jruby.RubyObject;
15
+ import org.jruby.runtime.Helpers;
16
+ import org.jruby.runtime.builtin.IRubyObject;
17
+ import org.jruby.javasupport.JavaUtil;
18
+ import org.jruby.RubyModule;
19
+ import org.jruby.exceptions.RaiseException;
20
+
13
21
  /**
14
- * the JRubyBolt class is a simple proxy class to the actual bolt implementation in JRuby.
15
- * this proxy is required to bypass the serialization/deserialization process when dispatching
16
- * the bolts to the workers. JRuby does not yet support serialization from Java
17
- * (Java serialization call on a JRuby class).
22
+ * the JRubyBolt class is a proxy class to the actual bolt implementation in JRuby.
23
+ * this proxy is required to bypass the serialization/deserialization issues of JRuby objects.
24
+ * JRuby classes do not support Java serialization.
18
25
  *
19
- * Note that the JRuby bolt proxy class is instanciated in the prepare method which is called after
20
- * deserialization at the worker and in the declareOutputFields method which is called once before
21
- * serialization at topology creation.
26
+ * Note that the JRuby bolt class is instanciated in the prepare method which is called after
27
+ * deserialization at the worker and in the declareOutputFields & getComponentConfiguration
28
+ * methods which are called once before serialization at topology creation.
22
29
  */
23
30
  public class JRubyBatchBolt extends BaseBatchBolt {
24
- IBatchBolt _proxyBolt;
25
- String _realBoltClassName;
26
- String _baseClassPath;
27
- String[] _fields;
31
+ private final String _realBoltClassName;
32
+ private final String[] _fields;
33
+ private final String _bootstrap;
34
+
35
+ // transient to avoid serialization
36
+ private transient IRubyObject _ruby_bolt;
37
+ private transient Ruby __ruby__;
28
38
 
29
39
  /**
30
40
  * create a new JRubyBolt
31
- *
32
- * @param baseClassPath the topology/project base JRuby class file path
41
+ *
42
+ * @param baseClassPath the topology/project base JRuby class file path
33
43
  * @param realBoltClassName the fully qualified JRuby bolt implementation class name
44
+ * @param fields the output fields names
34
45
  */
35
46
  public JRubyBatchBolt(String baseClassPath, String realBoltClassName, String[] fields) {
36
- _baseClassPath = baseClassPath;
37
47
  _realBoltClassName = realBoltClassName;
38
48
  _fields = fields;
49
+ _bootstrap = "require '" + baseClassPath + "'";
39
50
  }
40
51
 
41
52
  @Override
42
- public void prepare(final Map stormConf, final TopologyContext context, final BatchOutputCollector collector, final Object id) {
43
- // create instance of the jruby class here, after deserialization in the workers.
44
- _proxyBolt = newProxyBolt(_baseClassPath, _realBoltClassName);
45
- _proxyBolt.prepare(stormConf, context, collector, id);
53
+ public void prepare(final Map conf, final TopologyContext context, final BatchOutputCollector collector, final Object id) {
54
+ _ruby_bolt = initialize_ruby_bolt();
55
+ IRubyObject ruby_conf = JavaUtil.convertJavaToRuby(__ruby__, conf);
56
+ IRubyObject ruby_context = JavaUtil.convertJavaToRuby(__ruby__, context);
57
+ IRubyObject ruby_collector = JavaUtil.convertJavaToRuby(__ruby__, collector);
58
+ IRubyObject ruby_id = JavaUtil.convertJavaToRuby(__ruby__, id);
59
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_bolt, "prepare", ruby_conf, ruby_context, ruby_collector, ruby_id);
46
60
  }
47
61
 
48
62
  @Override
49
63
  public void execute(Tuple input) {
50
- _proxyBolt.execute(input);
64
+ IRubyObject ruby_input = JavaUtil.convertJavaToRuby(__ruby__, input);
65
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_bolt, "execute", ruby_input);
51
66
  }
52
67
 
53
68
  @Override
54
69
  public void finishBatch() {
55
- _proxyBolt.finishBatch();
70
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_bolt, "finish_batch");
56
71
  }
57
72
 
58
73
  @Override
59
74
  public void declareOutputFields(OutputFieldsDeclarer declarer) {
60
- // declareOutputFields is executed in the topology creation time, before serialisation.
61
- // do not set the _proxyBolt instance variable here to avoid JRuby serialization
62
- // issues. Just create tmp bolt instance to call declareOutputFields.
63
75
  if (_fields.length > 0) {
64
76
  declarer.declare(new Fields(_fields));
65
77
  } else {
66
- IBatchBolt bolt = newProxyBolt(_baseClassPath, _realBoltClassName);
67
- bolt.declareOutputFields(declarer);
78
+ IRubyObject ruby_bolt = initialize_ruby_bolt();
79
+ IRubyObject ruby_declarer = JavaUtil.convertJavaToRuby(__ruby__, declarer);
80
+ Helpers.invoke(__ruby__.getCurrentContext(), ruby_bolt, "declare_output_fields", ruby_declarer);
68
81
  }
69
82
  }
70
83
 
71
84
  @Override
72
85
  public Map<String, Object> getComponentConfiguration() {
73
86
  // getComponentConfiguration is executed in the topology creation time, before serialisation.
74
- // do not set the _proxyBolt instance variable here to avoid JRuby serialization
75
- // issues. Just create tmp bolt instance to call declareOutputFields.
76
- IBatchBolt bolt = newProxyBolt(_baseClassPath, _realBoltClassName);
77
- return bolt.getComponentConfiguration();
87
+ // just create tmp bolt instance to call getComponentConfiguration.
88
+
89
+ IRubyObject ruby_bolt = initialize_ruby_bolt();
90
+ IRubyObject ruby_result = Helpers.invoke(__ruby__.getCurrentContext(), ruby_bolt, "get_component_configuration");
91
+ return (Map)ruby_result.toJava(Map.class);
78
92
  }
79
-
80
93
 
81
- private static IBatchBolt newProxyBolt(String baseClassPath, String realBoltClassName) {
94
+ private IRubyObject initialize_ruby_bolt() {
95
+ __ruby__ = Ruby.getGlobalRuntime();
96
+
97
+ RubyModule ruby_class;
82
98
  try {
83
- redstorm.proxy.BatchBolt proxy = new redstorm.proxy.BatchBolt(baseClassPath, realBoltClassName);
84
- return proxy;
99
+ ruby_class = __ruby__.getClassFromPath(_realBoltClassName);
85
100
  }
86
- catch (Exception e) {
87
- throw new RuntimeException(e);
101
+ catch (RaiseException e) {
102
+ // after deserialization we need to recreate ruby environment
103
+ __ruby__.evalScriptlet(_bootstrap);
104
+ ruby_class = __ruby__.getClassFromPath(_realBoltClassName);
88
105
  }
106
+ return Helpers.invoke(__ruby__.getCurrentContext(), ruby_class, "new");
89
107
  }
90
108
  }
@@ -6,83 +6,118 @@ import storm.trident.operation.TridentCollector;
6
6
  import storm.trident.spout.IBatchSpout;
7
7
  import java.util.Map;
8
8
 
9
+ import org.jruby.Ruby;
10
+ import org.jruby.RubyObject;
11
+ import org.jruby.runtime.Helpers;
12
+ import org.jruby.runtime.builtin.IRubyObject;
13
+ import org.jruby.javasupport.JavaUtil;
14
+ import org.jruby.RubyModule;
15
+ import org.jruby.exceptions.RaiseException;
16
+
9
17
  /**
10
- * the JRubySpout class is a simple proxy class to the actual spout implementation in JRuby.
11
- * this proxy is required to bypass the serialization/deserialization process when dispatching
12
- * the spout to the workers. JRuby does not yet support serialization from Java
13
- * (Java serialization call on a JRuby class).
18
+ * the JRubySpout class is a proxy class to the actual spout implementation in JRuby.
19
+ * this proxy is required to bypass the serialization/deserialization issues of JRuby objects.
20
+ * JRuby classes do not support Java serialization.
14
21
  *
15
- * Note that the JRuby spout proxy class is instanciated in the open method which is called after
16
- * deserialization at the worker and in both the declareOutputFields and isDistributed methods which
17
- * are called once before serialization at topology creation.
22
+ * Note that the JRuby spout class is instanciated in the open method which is called after
23
+ * deserialization at the worker and in the declareOutputFields & getComponentConfiguration
24
+ * methods which are called once before serialization at topology creation.
18
25
  */
19
26
  public class JRubyBatchSpout implements IBatchSpout {
20
- IBatchSpout _proxySpout;
21
- String _realSpoutClassName;
22
- String _baseClassPath;
23
-
27
+ private final String _realSpoutClassName;
28
+ private final String[] _fields;
29
+ private final String _bootstrap;
30
+
31
+ // transient to avoid serialization
32
+ private transient IRubyObject _ruby_spout;
33
+ private transient Ruby __ruby__;
34
+
24
35
  /**
25
- * create a new JRubySpout
26
- *
27
- * @param baseClassPath the topology/project base JRuby class file path
36
+ * create a new JRubyBatchSpout
37
+ *
38
+ * @param baseClassPath the topology/project base JRuby class file path
28
39
  * @param realSpoutClassName the fully qualified JRuby spout implementation class name
40
+ * @param fields the output fields names
29
41
  */
30
42
  public JRubyBatchSpout(String baseClassPath, String realSpoutClassName) {
31
- _baseClassPath = baseClassPath;
32
43
  _realSpoutClassName = realSpoutClassName;
44
+ _fields = null;
45
+ _bootstrap = "require '" + baseClassPath + "'";
46
+ }
47
+
48
+ /* constructor for compatibility with JRubySpout signature */
49
+ public JRubyBatchSpout(String baseClassPath, String realSpoutClassName, String[] fields) {
50
+ _realSpoutClassName = realSpoutClassName;
51
+ _fields = fields;
52
+ _bootstrap = "require '" + baseClassPath + "'";
33
53
  }
34
54
 
35
55
  @Override
36
56
  public void open(final Map conf, final TopologyContext context) {
37
- // create instance of the jruby proxy class here, after deserialization in the workers.
38
- _proxySpout = newProxySpout(_baseClassPath, _realSpoutClassName);
39
- _proxySpout.open(conf, context);
57
+ // // create instance of the jruby proxy class here, after deserialization in the workers.
58
+ // _proxySpout = newProxySpout(_baseClassPath, _realSpoutClassName);
59
+ // _proxySpout.open(conf, context);
60
+
61
+
62
+ _ruby_spout = initialize_ruby_spout();
63
+ IRubyObject ruby_conf = JavaUtil.convertJavaToRuby(__ruby__, conf);
64
+ IRubyObject ruby_context = JavaUtil.convertJavaToRuby(__ruby__, context);
65
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_spout, "open", ruby_conf, ruby_context);
40
66
  }
41
67
 
42
68
  @Override
43
69
  public void emitBatch(long batchId, TridentCollector collector) {
44
- _proxySpout.emitBatch(batchId, collector);
45
- }
70
+ // _proxySpout.emitBatch(batchId, collector);
71
+
72
+ IRubyObject ruby_batch_id = JavaUtil.convertJavaToRuby(__ruby__, batchId);
73
+ IRubyObject ruby_collector = JavaUtil.convertJavaToRuby(__ruby__, collector);
74
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_spout, "emit_batch", ruby_batch_id, ruby_collector);
75
+ }
46
76
 
47
77
  @Override
48
78
  public void close() {
49
- _proxySpout.close();
79
+ // _proxySpout.close();
80
+
81
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_spout, "close");
50
82
  }
51
83
 
52
84
  @Override
53
85
  public void ack(long batchId) {
54
- _proxySpout.ack(batchId);
86
+ // _proxySpout.ack(batchId);
87
+
88
+ IRubyObject ruby_batch_id = JavaUtil.convertJavaToRuby(__ruby__, batchId);
89
+ Helpers.invoke(__ruby__.getCurrentContext(), _ruby_spout, "ack", ruby_batch_id);
55
90
  }
56
91
 
57
92
  @Override
58
93
  public Fields getOutputFields() {
59
- if (_proxySpout == null) {
60
- // getOutputFields is executed in the topology creation time before serialisation.
61
- // do not set the _proxySpout instance variable here to avoid JRuby serialization
62
- // issues. Just create tmp spout instance to call getOutputFields.
63
- IBatchSpout spout = newProxySpout(_baseClassPath, _realSpoutClassName);
64
- return spout.getOutputFields();
65
- } else {
66
- return _proxySpout.getOutputFields();
67
- }
94
+ IRubyObject ruby_spout = initialize_ruby_spout();
95
+ IRubyObject ruby_result = Helpers.invoke(__ruby__.getCurrentContext(), ruby_spout, "get_output_fields");
96
+ return (Fields)ruby_result.toJava(Fields.class);
68
97
  }
69
98
 
70
99
  @Override
71
100
  public Map<String, Object> getComponentConfiguration() {
72
- // getComponentConfiguration is executed in the topology creation time before serialisation.
73
- // do not set the _proxySpout instance variable here to avoid JRuby serialization
74
- // issues. Just create tmp spout instance to call declareOutputFields.
75
- IBatchSpout spout = newProxySpout(_baseClassPath, _realSpoutClassName);
76
- return spout.getComponentConfiguration();
101
+ // getComponentConfiguration is executed in the topology creation time, before serialisation.
102
+ // just create tmp spout instance to call getComponentConfiguration.
103
+
104
+ IRubyObject ruby_spout = initialize_ruby_spout();
105
+ IRubyObject ruby_result = Helpers.invoke(__ruby__.getCurrentContext(), ruby_spout, "get_component_configuration");
106
+ return (Map)ruby_result.toJava(Map.class);
77
107
  }
78
-
79
- private static IBatchSpout newProxySpout(String baseClassPath, String realSpoutClassName) {
108
+
109
+ private IRubyObject initialize_ruby_spout() {
110
+ __ruby__ = Ruby.getGlobalRuntime();
111
+
112
+ RubyModule ruby_class;
80
113
  try {
81
- redstorm.proxy.BatchSpout proxy = new redstorm.proxy.BatchSpout(baseClassPath, realSpoutClassName);
82
- return proxy;
114
+ ruby_class = __ruby__.getClassFromPath(_realSpoutClassName);
83
115
  }
84
- catch (Exception e) {
85
- throw new RuntimeException(e);
116
+ catch (RaiseException e) {
117
+ // after deserialization we need to recreate ruby environment
118
+ __ruby__.evalScriptlet(_bootstrap);
119
+ ruby_class = __ruby__.getClassFromPath(_realSpoutClassName);
86
120
  }
121
+ return Helpers.invoke(__ruby__.getCurrentContext(), ruby_class, "new");
87
122
  }
88
123
  }