redstorm 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGELOG.md +9 -0
  2. data/README.md +206 -103
  3. data/examples/native/cluster_word_count_topology.rb +5 -5
  4. data/examples/native/local_exclamation_topology.rb +8 -8
  5. data/examples/native/local_exclamation_topology2.rb +7 -7
  6. data/examples/native/local_redis_word_count_topology.rb +7 -8
  7. data/examples/native/local_word_count_topology.rb +5 -5
  8. data/examples/simple/exclamation_topology.rb +7 -11
  9. data/examples/simple/exclamation_topology2.rb +10 -12
  10. data/examples/simple/hello_world_topology.rb +22 -0
  11. data/examples/simple/kafka_topology.rb +2 -1
  12. data/examples/simple/redis_word_count_topology.rb +3 -5
  13. data/examples/simple/ruby_version_topology.rb +7 -1
  14. data/examples/simple/word_count_topology.rb +8 -10
  15. data/ivy/settings.xml +1 -0
  16. data/ivy/storm_dependencies.xml +8 -0
  17. data/ivy/topology_dependencies.xml +7 -0
  18. data/lib/red_storm.rb +1 -0
  19. data/lib/red_storm/application.rb +9 -7
  20. data/lib/red_storm/configurator.rb +1 -1
  21. data/lib/red_storm/proxy/batch_bolt.rb +63 -0
  22. data/lib/red_storm/proxy/batch_committer_bolt.rb +52 -0
  23. data/lib/red_storm/proxy/batch_spout.rb +59 -0
  24. data/lib/red_storm/proxy/proxy_function.rb +40 -0
  25. data/lib/red_storm/proxy/transactional_committer_spout.rb +47 -0
  26. data/lib/red_storm/proxy/transactional_spout.rb +46 -0
  27. data/lib/red_storm/simple_drpc_topology.rb +87 -0
  28. data/lib/red_storm/simple_topology.rb +14 -4
  29. data/lib/red_storm/topology_launcher.rb +22 -3
  30. data/lib/red_storm/version.rb +1 -1
  31. data/lib/tasks/red_storm.rake +66 -104
  32. data/redstorm.gemspec +24 -0
  33. data/src/main/redstorm/storm/jruby/JRubyBatchBolt.java +90 -0
  34. data/src/main/redstorm/storm/jruby/JRubyBatchCommitterBolt.java +9 -0
  35. data/src/main/redstorm/storm/jruby/JRubyBatchSpout.java +88 -0
  36. data/src/main/redstorm/storm/jruby/JRubyProxyFunction.java +51 -0
  37. data/src/main/redstorm/storm/jruby/JRubyShellSpout.java +1 -1
  38. data/src/main/redstorm/storm/jruby/JRubyTransactionalBolt.java +90 -0
  39. data/src/main/redstorm/storm/jruby/JRubyTransactionalCommitterBolt.java +31 -0
  40. data/src/main/redstorm/storm/jruby/JRubyTransactionalCommitterSpout.java +44 -0
  41. data/src/main/redstorm/storm/jruby/JRubyTransactionalSpout.java +89 -0
  42. metadata +35 -14
  43. data/examples/native/Gemfile +0 -2
@@ -1,23 +1,37 @@
1
1
  require 'java'
2
2
 
3
+ # This hack get rif of the "Use RbConfig instead of obsolete and deprecated Config"
4
+ # deprecation warning that is triggered by "java_import 'backtype.storm.Config'".
5
+ Object.send :remove_const, :Config
6
+ Config = RbConfig
7
+
3
8
  # see https://github.com/colinsurprenant/redstorm/issues/7
4
9
  module Backtype
5
10
  java_import 'backtype.storm.Config'
6
11
  end
7
12
 
8
13
  java_import 'backtype.storm.LocalCluster'
14
+ java_import 'backtype.storm.LocalDRPC'
9
15
  java_import 'backtype.storm.StormSubmitter'
10
16
  java_import 'backtype.storm.topology.TopologyBuilder'
17
+ java_import 'backtype.storm.coordination.BatchBoltExecutor'
18
+ java_import 'backtype.storm.drpc.LinearDRPCTopologyBuilder'
11
19
  java_import 'backtype.storm.tuple.Fields'
12
20
  java_import 'backtype.storm.tuple.Tuple'
13
21
  java_import 'backtype.storm.tuple.Values'
14
22
 
15
23
  java_import 'redstorm.storm.jruby.JRubyBolt'
16
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'
17
31
 
18
32
  java_package 'redstorm'
19
33
 
20
- # TopologyLauncher is the application entry point when launching a topology. Basically it will
34
+ # TopologyLauncher is the application entry point when launching a topology. Basically it will
21
35
  # call require on the specified Ruby topology class file path and call its start method
22
36
  class TopologyLauncher
23
37
 
@@ -36,14 +50,19 @@ class TopologyLauncher
36
50
  $:.unshift File.expand_path(launch_path + '/lib')
37
51
  $:.unshift File.expand_path(launch_path + '/target/lib')
38
52
 
39
- require "#{class_path}"
53
+ require "#{class_path}"
54
+
55
+ if RedStorm::Configuration.topology_class.nil? || !RedStorm::Configuration.topology_class.method_defined?(:start)
56
+ puts("\nERROR: invalid topology class. make sure your topology class is a subclass of one of the DSL topology classes or that your class sets RedStorm::Configuration.topology_class and defines the start method\n\n")
57
+ exit(1)
58
+ end
40
59
 
41
60
  topology_name = RedStorm::Configuration.topology_class.respond_to?(:topology_name) ? "/#{RedStorm::Configuration.topology_class.topology_name}" : ''
42
61
  puts("RedStorm v#{RedStorm::VERSION} starting topology #{RedStorm::Configuration.topology_class.name}#{topology_name} in #{env.to_s} environment")
43
62
  RedStorm::Configuration.topology_class.new.start(class_path, env)
44
63
  end
45
64
 
46
- private
65
+ private
47
66
 
48
67
  def self.camel_case(s)
49
68
  s.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
@@ -1,3 +1,3 @@
1
1
  module RedStorm
2
- VERSION = '0.6.4'
2
+ VERSION = '0.6.5'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  begin
2
2
  require 'ant'
3
3
  rescue
4
- puts("error: unable to load Ant, make sure Ant is installed and in your PATH")
4
+ puts("ERROR: unable to load Ant, make sure Ant is installed, in your PATH and $ANT_HOME is defined properly")
5
5
  puts("\nerror detail:\n#{$!}")
6
6
  exit(1)
7
7
  end
@@ -10,18 +10,7 @@ require 'jruby/jrubyc'
10
10
  require 'red_storm'
11
11
  require 'red_storm/application'
12
12
 
13
- DEP_STORM_VERSION = "0.8.1"
14
- DEP_JRUBY_VERSION = "1.6.8"
15
- INSTALL_IVY_VERSION = "2.2.0"
16
-
17
- DEFAULT_DEPENDENCIES = {
18
- :storm_artifacts => [
19
- "storm:storm:#{DEP_STORM_VERSION}, transitive=true",
20
- ],
21
- :topology_artifacts => [
22
- "org.jruby:jruby-complete:#{DEP_JRUBY_VERSION}, transitive=false",
23
- ],
24
- }
13
+ INSTALL_IVY_VERSION = "2.3.0"
25
14
 
26
15
  task :launch, :env, :ruby_mode, :class_file do |t, args|
27
16
  # use ruby mode parameter or default to current interpreter version
@@ -32,7 +21,7 @@ task :launch, :env, :ruby_mode, :class_file do |t, args|
32
21
  RedStorm::Application.local_storm_command(args[:class_file], args[:ruby_mode])
33
22
  when "cluster"
34
23
  unless File.exist?(TARGET_CLUSTER_JAR)
35
- puts("error: cluster jar file #{TARGET_CLUSTER_JAR} not found. Generate it usingw $redstorm jar DIR1 [DIR2, ...]")
24
+ puts("error: cluster jar file #{TARGET_CLUSTER_JAR} not found. Generate it using $redstorm jar DIR1 [DIR2, ...]")
36
25
  exit(1)
37
26
  end
38
27
  RedStorm::Application.cluster_storm_command(args[:class_file], args[:ruby_mode])
@@ -45,24 +34,24 @@ task :launch, :env, :ruby_mode, :class_file do |t, args|
45
34
  end
46
35
 
47
36
  task :clean do
48
- ant.delete :dir => TARGET_DIR
37
+ ant.delete 'dir' => TARGET_DIR
49
38
  end
50
39
 
51
40
  task :clean_jar do
52
- ant.delete :file => TARGET_CLUSTER_JAR
41
+ ant.delete 'file' => TARGET_CLUSTER_JAR
53
42
  end
54
43
 
55
44
  task :setup do
56
45
  puts("\n--> Setting up target directories")
57
- ant.mkdir :dir => TARGET_DIR
58
- ant.mkdir :dir => TARGET_CLASSES_DIR
59
- ant.mkdir :dir => TARGET_DEPENDENCY_DIR
60
- ant.mkdir :dir => TARGET_SRC_DIR
61
- ant.mkdir :dir => TARGET_GEM_DIR
62
- ant.mkdir :dir => TARGET_SPECS_DIR
63
- ant.path :id => 'classpath' do
64
- fileset :dir => TARGET_DEPENDENCY_DIR
65
- fileset :dir => TARGET_CLASSES_DIR
46
+ ant.mkdir 'dir' => TARGET_DIR
47
+ ant.mkdir 'dir' => TARGET_CLASSES_DIR
48
+ ant.mkdir 'dir' => TARGET_DEPENDENCY_DIR
49
+ ant.mkdir 'dir' => TARGET_SRC_DIR
50
+ ant.mkdir 'dir' => TARGET_GEM_DIR
51
+ ant.mkdir 'dir' => TARGET_SPECS_DIR
52
+ ant.path 'id' => 'classpath' do
53
+ fileset 'dir' => TARGET_DEPENDENCY_DIR
54
+ fileset 'dir' => TARGET_CLASSES_DIR
66
55
  end
67
56
  end
68
57
 
@@ -111,18 +100,23 @@ task :bundle, [:groups] => :setup do |t, args|
111
100
  defaulted_args = {:groups => 'default'}.merge(args.to_hash.delete_if{|k, v| v.to_s.empty?})
112
101
  groups = defaulted_args[:groups].split(':').map(&:to_sym)
113
102
  Bundler.definition.specs_for(groups).each do |spec|
114
- unless spec.full_name =~ /^bundler-\d+/
115
- destination_path = "#{TARGET_GEM_DIR}/#{spec.full_name}"
116
- unless File.directory?(destination_path)
117
- puts("installing gem #{spec.full_name} into #{destination_path}")
118
- # copy the actual gem dir
119
- FileUtils.cp_r(spec.full_gem_path, destination_path)
120
- # copy the gemspec into the specifications/ dir
121
- FileUtils.cp_r(spec.loaded_from, TARGET_SPECS_DIR)
122
- # strip the .git directory from git dependencies, it can be huge
123
- FileUtils.rm_rf("#{destination_path}/.git")
124
- end
125
- end
103
+ next if spec.name == 'bundler'
104
+
105
+ # try to avoid infinite recursion
106
+ next if TARGET_GEM_DIR.start_with?(spec.full_gem_path)
107
+
108
+ destination_path = "#{TARGET_GEM_DIR}/#{spec.full_name}"
109
+ next if File.directory?(destination_path)
110
+
111
+ puts("installing gem #{spec.full_name} into #{destination_path}")
112
+ # copy the actual gem dir
113
+ FileUtils.cp_r(spec.full_gem_path, destination_path)
114
+ # copy the evaluated gemspec into the specifications/ dir (we
115
+ # may not have enough info to reconstruct once we delete the
116
+ # .git directory)
117
+ File.open(File.join(TARGET_SPECS_DIR, File.basename(spec.loaded_from)), 'w'){|f| f.write(spec.to_ruby)}
118
+ # strip the .git directory from git dependencies, it can be huge
119
+ FileUtils.rm_rf("#{destination_path}/.git")
126
120
  end
127
121
  end
128
122
 
@@ -130,21 +124,21 @@ namespace :ivy do
130
124
  task :download do
131
125
  mkdir_p DST_IVY_DIR
132
126
  ant.get({
133
- :src => "http://repo1.maven.org/maven2/org/apache/ivy/ivy/#{INSTALL_IVY_VERSION}/ivy-#{INSTALL_IVY_VERSION}.jar",
134
- :dest => "#{DST_IVY_DIR}/ivy-#{INSTALL_IVY_VERSION}.jar",
135
- :usetimestamp => true,
127
+ 'src' => "http://repo1.maven.org/maven2/org/apache/ivy/ivy/#{INSTALL_IVY_VERSION}/ivy-#{INSTALL_IVY_VERSION}.jar",
128
+ 'dest' => "#{DST_IVY_DIR}/ivy-#{INSTALL_IVY_VERSION}.jar",
129
+ 'usetimestamp' => true,
136
130
  })
137
131
  end
138
132
 
139
133
  task :install => :download do
140
- ant.path :id => 'ivy.lib.path' do
141
- fileset :dir => DST_IVY_DIR, :includes => '*.jar'
134
+ ant.path 'id' => 'ivy.lib.path' do
135
+ fileset 'dir' => DST_IVY_DIR, 'includes' => '*.jar'
142
136
  end
143
137
 
144
138
  ant.taskdef({
145
- :resource => "org/apache/ivy/ant/antlib.xml",
146
- :classpathref => "ivy.lib.path",
147
- #:uri => "antlib:org.apache.ivy.ant",
139
+ 'resource' => "org/apache/ivy/ant/antlib.xml",
140
+ 'classpathref' => "ivy.lib.path",
141
+ #'uri' => "antlib:org.apache.ivy.ant",
148
142
  })
149
143
  end
150
144
  end
@@ -152,37 +146,32 @@ end
152
146
  task :deps => "ivy:install" do
153
147
  puts("\n--> Installing dependencies")
154
148
 
155
- dependencies = File.exists?(CUSTOM_DEPENDENCIES) ? eval(File.read(CUSTOM_DEPENDENCIES)) : DEFAULT_DEPENDENCIES
156
- ant.configure :file => File.exists?(CUSTOM_IVY_SETTINGS) ? CUSTOM_IVY_SETTINGS : DEFAULT_IVY_SETTINGS
149
+ ant.configure 'file' => File.exists?(CUSTOM_IVY_SETTINGS) ? CUSTOM_IVY_SETTINGS : DEFAULT_IVY_SETTINGS
157
150
 
158
- dependencies[:storm_artifacts].each do |dependency|
159
- artifact, transitive = dependency.split(/\s*,\s*/)
160
- ivy_retrieve(*artifact.split(':').concat([transitive.split(/\s*=\s*/).last, "#{TARGET_DEPENDENCY_DIR}/storm", "default"]))
161
- end
151
+ ant.resolve 'file' => File.exists?(CUSTOM_IVY_STORM_DEPENDENCIES) ? CUSTOM_IVY_STORM_DEPENDENCIES : DEFAULT_IVY_STORM_DEPENDENCIES
152
+ ant.retrieve 'pattern' => "#{TARGET_DEPENDENCY_DIR}/storm/[conf]/[artifact]-[revision].[ext]", 'sync' => "true"
162
153
 
163
- dependencies[:topology_artifacts].each do |dependency|
164
- artifact, transitive = dependency.split(/\s*,\s*/)
165
- ivy_retrieve(*artifact.split(':').concat([transitive.split(/\s*=\s*/).last, "#{TARGET_DEPENDENCY_DIR}/topology", "default"]))
166
- end
167
- end
154
+ ant.resolve 'file' => File.exists?(CUSTOM_IVY_TOPOLOGY_DEPENDENCIES) ? CUSTOM_IVY_TOPOLOGY_DEPENDENCIES : DEFAULT_IVY_TOPOLOGY_DEPENDENCIES
155
+ ant.retrieve 'pattern' => "#{TARGET_DEPENDENCY_DIR}/topology/[conf]/[artifact]-[revision].[ext]", 'sync' => "true"
156
+ end
168
157
 
169
158
  task :jar, [:include_dir] => [:clean_jar] do |t, args|
170
159
  puts("\n--> Generating JAR file #{TARGET_CLUSTER_JAR}")
171
160
 
172
- ant.jar :destfile => TARGET_CLUSTER_JAR do
161
+ ant.jar 'destfile' => TARGET_CLUSTER_JAR do
173
162
  # rejar all topology jars
174
163
  Dir["target/dependency/topology/default/*.jar"].each do |jar|
175
164
  puts("Extracting #{jar}")
176
- zipfileset :src => jar, :includes => "**/*"
165
+ zipfileset 'src' => jar, 'includes' => "**/*"
177
166
  end
178
- fileset :dir => TARGET_DIR do
179
- include :name => "gems/**"
167
+ fileset 'dir' => TARGET_DIR do
168
+ include 'name' => "gems/**"
180
169
  end
181
- fileset :dir => TARGET_CLASSES_DIR
170
+ fileset 'dir' => TARGET_CLASSES_DIR
182
171
  # red_storm.rb and red_storm/* must be in root of jar so that "require 'red_storm'"
183
172
  # in bolts/spouts works in jar context
184
- fileset :dir => TARGET_LIB_DIR do
185
- exclude :name => "tasks/**"
173
+ fileset 'dir' => TARGET_LIB_DIR do
174
+ exclude 'name' => "tasks/**"
186
175
  end
187
176
  if args[:include_dir]
188
177
  dirs = args[:include_dir].split(":")
@@ -192,19 +181,19 @@ task :jar, [:include_dir] => [:clean_jar] do |t, args|
192
181
  resources_dirs = Dir.glob("#{dir}/**/resources")
193
182
  resources_dirs.each do |resources_dir|
194
183
  resources_parent = resources_dir.gsub("/resources", "")
195
- fileset :dir => resources_parent do
196
- include :name => "resources/**/*"
184
+ fileset 'dir' => resources_parent do
185
+ include 'name' => "resources/**/*"
197
186
  end
198
187
  end
199
188
  end
200
189
 
201
190
  # include complete source dir tree (note we don't care about potential duplicated resources dir)
202
- fileset :dir => CWD do
203
- dirs.each{|dir| include :name => "#{dir}/**/*"}
191
+ fileset 'dir' => CWD do
192
+ dirs.each{|dir| include 'name' => "#{dir}/**/*"}
204
193
  end
205
194
  end
206
195
  manifest do
207
- attribute :name => "Main-Class", :value => "redstorm.TopologyLauncher"
196
+ attribute 'name' => "Main-Class", 'value' => "redstorm.TopologyLauncher"
208
197
  end
209
198
  end
210
199
  puts("\nRedStorm generated JAR file #{TARGET_CLUSTER_JAR}")
@@ -213,15 +202,15 @@ end
213
202
  def build_java_dir(source_folder)
214
203
  puts("\n--> Compiling Java")
215
204
  ant.javac(
216
- :srcdir => source_folder,
217
- :destdir => TARGET_CLASSES_DIR,
218
- :classpathref => 'classpath',
219
- :source => "1.6",
220
- :target => "1.6",
221
- :debug => "yes",
222
- :includeantruntime => "no",
223
- :verbose => false,
224
- :listfiles => true
205
+ 'srcdir' => source_folder,
206
+ 'destdir' => TARGET_CLASSES_DIR,
207
+ 'classpathref' => 'classpath',
208
+ 'source' => "1.7",
209
+ 'target' => "1.7",
210
+ 'debug' => "yes",
211
+ 'includeantruntime' => "no",
212
+ 'verbose' => false,
213
+ 'listfiles' => true
225
214
  ) do
226
215
  # compilerarg :value => "-Xlint:unchecked"
227
216
  end
@@ -242,30 +231,3 @@ def build_jruby(source_path)
242
231
  status = JRuby::Compiler::compile_argv(argv)
243
232
  end
244
233
  end
245
-
246
- def truefalse(s)
247
- return true if s.to_s.downcase =~ /1|yes|true/
248
- return false if s.to_s.downcase =~ /0|no|false/
249
- nil
250
- end
251
-
252
- def ivy_retrieve(org, mod, rev, transitive, dir, conf)
253
- ant.resolve({
254
- :organisation => org,
255
- :module => mod,
256
- :revision => rev,
257
- :inline => true,
258
- :transitive => truefalse(transitive),
259
- :conf => conf,
260
- })
261
-
262
- ant.retrieve({
263
- :organisation => org,
264
- :module => mod,
265
- :revision => rev,
266
- :pattern => "#{dir}/[conf]/[artifact]-[revision].[ext]",
267
- :inline => true,
268
- :transitive => truefalse(transitive),
269
- :conf => conf,
270
- })
271
- end
@@ -0,0 +1,24 @@
1
+ libdir = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift libdir unless $:.include?(libdir)
3
+
4
+ require 'red_storm/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'redstorm'
8
+ s.version = RedStorm::VERSION
9
+ s.authors = ['Colin Surprenant']
10
+ s.email = ['colin.surprenant@gmail.com']
11
+ s.homepage = 'https://github.com/colinsurprenant/redstorm'
12
+ s.summary = 'JRuby on Storm'
13
+ s.description = 'JRuby integration & DSL for the Storm distributed realtime computation system'
14
+
15
+ s.rubyforge_project = 'redstorm'
16
+
17
+ s.files = Dir.glob("{lib/**/*}") + Dir.glob("{ivy/*.xml}") + Dir.glob("{examples/**/*}") + Dir.glob("{src/**/*.java}") + Dir.glob("{bin/**/*}") + %w(redstorm.gemspec Rakefile README.md CHANGELOG.md LICENSE.md)
18
+ s.require_paths = ['lib']
19
+ s.bindir = 'bin'
20
+ s.executables = ['redstorm']
21
+
22
+ s.add_development_dependency 'rspec', '~> 2.11.0'
23
+ s.add_runtime_dependency 'rake'
24
+ end
@@ -0,0 +1,90 @@
1
+ package redstorm.storm.jruby;
2
+
3
+ import backtype.storm.task.OutputCollector;
4
+ import backtype.storm.task.TopologyContext;
5
+ import backtype.storm.topology.base.BaseBatchBolt;
6
+ import backtype.storm.coordination.BatchOutputCollector;
7
+ import backtype.storm.coordination.IBatchBolt;
8
+ import backtype.storm.topology.OutputFieldsDeclarer;
9
+ import backtype.storm.tuple.Tuple;
10
+ import backtype.storm.tuple.Fields;
11
+ import java.util.Map;
12
+
13
+ /**
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).
18
+ *
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.
22
+ */
23
+ public class JRubyBatchBolt extends BaseBatchBolt {
24
+ IBatchBolt _proxyBolt;
25
+ String _realBoltClassName;
26
+ String _baseClassPath;
27
+ String[] _fields;
28
+
29
+ /**
30
+ * create a new JRubyBolt
31
+ *
32
+ * @param baseClassPath the topology/project base JRuby class file path
33
+ * @param realBoltClassName the fully qualified JRuby bolt implementation class name
34
+ */
35
+ public JRubyBatchBolt(String baseClassPath, String realBoltClassName, String[] fields) {
36
+ _baseClassPath = baseClassPath;
37
+ _realBoltClassName = realBoltClassName;
38
+ _fields = fields;
39
+ }
40
+
41
+ @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);
46
+ }
47
+
48
+ @Override
49
+ public void execute(Tuple input) {
50
+ _proxyBolt.execute(input);
51
+ }
52
+
53
+ @Override
54
+ public void finishBatch() {
55
+ _proxyBolt.finishBatch();
56
+ }
57
+
58
+ @Override
59
+ 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
+ if (_fields.length > 0) {
64
+ declarer.declare(new Fields(_fields));
65
+ } else {
66
+ IBatchBolt bolt = newProxyBolt(_baseClassPath, _realBoltClassName);
67
+ bolt.declareOutputFields(declarer);
68
+ }
69
+ }
70
+
71
+ @Override
72
+ public Map<String, Object> getComponentConfiguration() {
73
+ // 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();
78
+ }
79
+
80
+
81
+ private static IBatchBolt newProxyBolt(String baseClassPath, String realBoltClassName) {
82
+ try {
83
+ redstorm.proxy.BatchBolt proxy = new redstorm.proxy.BatchBolt(baseClassPath, realBoltClassName);
84
+ return proxy;
85
+ }
86
+ catch (Exception e) {
87
+ throw new RuntimeException(e);
88
+ }
89
+ }
90
+ }