kb-redstorm 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/CHANGELOG.md +74 -0
  2. data/LICENSE.md +13 -0
  3. data/README.md +375 -0
  4. data/Rakefile +11 -0
  5. data/bin/redstorm +15 -0
  6. data/examples/native/Gemfile +2 -0
  7. data/examples/native/cluster_word_count_topology.rb +25 -0
  8. data/examples/native/exclamation_bolt.rb +21 -0
  9. data/examples/native/local_exclamation_topology.rb +31 -0
  10. data/examples/native/local_exclamation_topology2.rb +48 -0
  11. data/examples/native/local_redis_word_count_topology.rb +69 -0
  12. data/examples/native/local_word_count_topology.rb +27 -0
  13. data/examples/native/random_sentence_spout.rb +30 -0
  14. data/examples/native/split_sentence_bolt.rb +20 -0
  15. data/examples/native/word_count_bolt.rb +26 -0
  16. data/examples/shell/resources/splitsentence.py +9 -0
  17. data/examples/shell/resources/storm.py +206 -0
  18. data/examples/shell/shell_topology.rb +41 -0
  19. data/examples/simple/exclamation_bolt.rb +10 -0
  20. data/examples/simple/exclamation_topology.rb +45 -0
  21. data/examples/simple/exclamation_topology2.rb +45 -0
  22. data/examples/simple/kafka_topology.rb +55 -0
  23. data/examples/simple/random_sentence_spout.rb +21 -0
  24. data/examples/simple/redis_word_count_topology.rb +61 -0
  25. data/examples/simple/ruby_version_topology.rb +32 -0
  26. data/examples/simple/split_sentence_bolt.rb +33 -0
  27. data/examples/simple/word_count_bolt.rb +19 -0
  28. data/examples/simple/word_count_topology.rb +38 -0
  29. data/ivy/settings.xml +11 -0
  30. data/lib/red_storm.rb +9 -0
  31. data/lib/red_storm/application.rb +85 -0
  32. data/lib/red_storm/configuration.rb +16 -0
  33. data/lib/red_storm/configurator.rb +26 -0
  34. data/lib/red_storm/environment.rb +41 -0
  35. data/lib/red_storm/loggable.rb +15 -0
  36. data/lib/red_storm/proxy/batch_spout.rb +71 -0
  37. data/lib/red_storm/proxy/bolt.rb +63 -0
  38. data/lib/red_storm/proxy/proxy_function.rb +48 -0
  39. data/lib/red_storm/proxy/spout.rb +87 -0
  40. data/lib/red_storm/simple_bolt.rb +135 -0
  41. data/lib/red_storm/simple_drpc_topology.rb +87 -0
  42. data/lib/red_storm/simple_spout.rb +184 -0
  43. data/lib/red_storm/simple_topology.rb +209 -0
  44. data/lib/red_storm/topology_launcher.rb +54 -0
  45. data/lib/red_storm/version.rb +3 -0
  46. data/lib/tasks/red_storm.rake +272 -0
  47. data/src/main/redstorm/storm/jruby/JRubyBatchSpout.java +89 -0
  48. data/src/main/redstorm/storm/jruby/JRubyBolt.java +88 -0
  49. data/src/main/redstorm/storm/jruby/JRubyProxyFunction.java +59 -0
  50. data/src/main/redstorm/storm/jruby/JRubyShellBolt.java +26 -0
  51. data/src/main/redstorm/storm/jruby/JRubyShellSpout.java +26 -0
  52. data/src/main/redstorm/storm/jruby/JRubySpout.java +107 -0
  53. metadata +134 -0
@@ -0,0 +1,54 @@
1
+ require 'java'
2
+
3
+ # see https://github.com/colinsurprenant/redstorm/issues/7
4
+ module Backtype
5
+ java_import 'backtype.storm.Config'
6
+ end
7
+
8
+ java_import 'backtype.storm.LocalCluster'
9
+ java_import 'backtype.storm.LocalDRPC'
10
+ java_import 'backtype.storm.StormSubmitter'
11
+ java_import 'backtype.storm.topology.TopologyBuilder'
12
+ java_import 'backtype.storm.drpc.LinearDRPCTopologyBuilder'
13
+ java_import 'backtype.storm.tuple.Fields'
14
+ java_import 'backtype.storm.tuple.Tuple'
15
+ java_import 'backtype.storm.tuple.Values'
16
+
17
+ java_import 'redstorm.storm.jruby.JRubyBolt'
18
+ java_import 'redstorm.storm.jruby.JRubySpout'
19
+ java_import 'redstorm.storm.jruby.JRubyBatchSpout'
20
+
21
+ java_package 'redstorm'
22
+
23
+ # TopologyLauncher is the application entry point when launching a topology. Basically it will
24
+ # call require on the specified Ruby topology class file path and call its start method
25
+ class TopologyLauncher
26
+
27
+ java_signature 'void main(String[])'
28
+ def self.main(args)
29
+ unless args.size > 1
30
+ puts("Usage: redstorm local|cluster topology_class_file_name")
31
+ exit(1)
32
+ end
33
+
34
+ env = args[0].to_sym
35
+ class_path = args[1]
36
+
37
+ launch_path = Dir.pwd
38
+ $:.unshift File.expand_path(launch_path)
39
+ $:.unshift File.expand_path(launch_path + '/lib')
40
+ $:.unshift File.expand_path(launch_path + '/target/lib')
41
+
42
+ require "#{class_path}"
43
+
44
+ topology_name = RedStorm::Configuration.topology_class.respond_to?(:topology_name) ? "/#{RedStorm::Configuration.topology_class.topology_name}" : ''
45
+ puts("RedStorm v#{RedStorm::VERSION} starting topology #{RedStorm::Configuration.topology_class.name}#{topology_name} in #{env.to_s} environment")
46
+ RedStorm::Configuration.topology_class.new.start(class_path, env)
47
+ end
48
+
49
+ private
50
+
51
+ def self.camel_case(s)
52
+ s.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module RedStorm
2
+ VERSION = '0.6.4'
3
+ end
@@ -0,0 +1,272 @@
1
+ begin
2
+ require 'ant'
3
+ rescue
4
+ puts("error: unable to load Ant, make sure Ant is installed, in your PATH")
5
+ puts(" and $ANT_HOME is defined properly.")
6
+ puts("\nerror detail:\n#{$!}")
7
+ exit(1)
8
+ end
9
+
10
+ require 'jruby/jrubyc'
11
+ require 'red_storm'
12
+ require 'red_storm/application'
13
+
14
+ DEP_STORM_VERSION = "0.8.2"
15
+ DEP_JRUBY_VERSION = "1.6.8"
16
+ INSTALL_IVY_VERSION = "2.2.0"
17
+
18
+ DEFAULT_DEPENDENCIES = {
19
+ :storm_artifacts => [
20
+ "storm:storm:#{DEP_STORM_VERSION}, transitive=true",
21
+ ],
22
+ :topology_artifacts => [
23
+ "org.jruby:jruby-complete:#{DEP_JRUBY_VERSION}, transitive=false",
24
+ ],
25
+ }
26
+
27
+ task :launch, :env, :ruby_mode, :class_file do |t, args|
28
+ # use ruby mode parameter or default to current interpreter version
29
+ version_token = RedStorm.jruby_mode_token(args[:ruby_mode])
30
+
31
+ command = case args[:env]
32
+ when "local"
33
+ RedStorm::Application.local_storm_command(args[:class_file], args[:ruby_mode])
34
+ when "cluster"
35
+ unless File.exist?(TARGET_CLUSTER_JAR)
36
+ puts("error: cluster jar file #{TARGET_CLUSTER_JAR} not found. Generate it usingw $redstorm jar DIR1 [DIR2, ...]")
37
+ exit(1)
38
+ end
39
+ RedStorm::Application.cluster_storm_command(args[:class_file], args[:ruby_mode])
40
+ end
41
+
42
+ puts("launching #{command}")
43
+ unless system(command)
44
+ puts($!)
45
+ end
46
+ end
47
+
48
+ task :clean do
49
+ ant.delete :dir => TARGET_DIR
50
+ end
51
+
52
+ task :clean_jar do
53
+ ant.delete :file => TARGET_CLUSTER_JAR
54
+ end
55
+
56
+ task :setup do
57
+ puts("\n--> Setting up target directories")
58
+ ant.mkdir :dir => TARGET_DIR
59
+ ant.mkdir :dir => TARGET_CLASSES_DIR
60
+ ant.mkdir :dir => TARGET_DEPENDENCY_DIR
61
+ ant.mkdir :dir => TARGET_SRC_DIR
62
+ ant.mkdir :dir => TARGET_GEM_DIR
63
+ ant.mkdir :dir => TARGET_SPECS_DIR
64
+ ant.path :id => 'classpath' do
65
+ fileset :dir => TARGET_DEPENDENCY_DIR
66
+ fileset :dir => TARGET_CLASSES_DIR
67
+ end
68
+ end
69
+
70
+ task :install => [:deps, :build] do
71
+ puts("\nRedStorm install completed. All dependencies installed in #{TARGET_DIR}")
72
+ end
73
+
74
+ task :examples do
75
+ if File.identical?(SRC_EXAMPLES, DST_EXAMPLES)
76
+ STDERR.puts("error: cannot copy examples into itself")
77
+ exit(1)
78
+ end
79
+ if File.exist?(DST_EXAMPLES)
80
+ STDERR.puts("error: directory #{DST_EXAMPLES} already exists")
81
+ exit(1)
82
+ end
83
+
84
+ puts("\n--> Installing examples into #{DST_EXAMPLES}")
85
+ FileUtils.mkdir(DST_EXAMPLES)
86
+ FileUtils.cp_r(Dir["#{SRC_EXAMPLES}/*"], DST_EXAMPLES)
87
+ end
88
+
89
+ task :copy_red_storm do
90
+ FileUtils.cp_r(REDSTORM_LIB_DIR, TARGET_DIR)
91
+ end
92
+
93
+ task :build => [:setup, :copy_red_storm] do
94
+ # compile the JRuby proxy classes to Java
95
+ build_jruby("#{REDSTORM_LIB_DIR}/red_storm/proxy")
96
+
97
+ # compile the generated Java proxy classes
98
+ build_java_dir("#{TARGET_SRC_DIR}")
99
+
100
+ # generate the JRuby topology launcher
101
+ build_jruby("#{REDSTORM_LIB_DIR}/red_storm/topology_launcher.rb")
102
+
103
+ # compile the JRuby proxy classes
104
+ build_java_dir("#{REDSTORM_JAVA_SRC_DIR}")
105
+
106
+ # compile the JRuby proxy classes
107
+ build_java_dir("#{TARGET_SRC_DIR}")
108
+ end
109
+
110
+ task :bundle, [:groups] => :setup do |t, args|
111
+ require 'bundler'
112
+ defaulted_args = {:groups => 'default'}.merge(args.to_hash.delete_if{|k, v| v.to_s.empty?})
113
+ groups = defaulted_args[:groups].split(':').map(&:to_sym)
114
+ Bundler.definition.specs_for(groups).each do |spec|
115
+ unless spec.full_name =~ /^bundler-\d+/
116
+ destination_path = "#{TARGET_GEM_DIR}/#{spec.full_name}"
117
+ unless File.directory?(destination_path)
118
+ puts("installing gem #{spec.full_name} into #{destination_path}")
119
+ # copy the actual gem dir
120
+ FileUtils.cp_r(spec.full_gem_path, destination_path)
121
+ # copy the gemspec into the specifications/ dir
122
+ FileUtils.cp_r(spec.loaded_from, TARGET_SPECS_DIR)
123
+ # strip the .git directory from git dependencies, it can be huge
124
+ FileUtils.rm_rf("#{destination_path}/.git")
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ namespace :ivy do
131
+ task :download do
132
+ mkdir_p DST_IVY_DIR
133
+ ant.get({
134
+ :src => "http://repo1.maven.org/maven2/org/apache/ivy/ivy/#{INSTALL_IVY_VERSION}/ivy-#{INSTALL_IVY_VERSION}.jar",
135
+ :dest => "#{DST_IVY_DIR}/ivy-#{INSTALL_IVY_VERSION}.jar",
136
+ :usetimestamp => true,
137
+ })
138
+ end
139
+
140
+ task :install => :download do
141
+ ant.path :id => 'ivy.lib.path' do
142
+ fileset :dir => DST_IVY_DIR, :includes => '*.jar'
143
+ end
144
+
145
+ ant.taskdef({
146
+ :resource => "org/apache/ivy/ant/antlib.xml",
147
+ :classpathref => "ivy.lib.path",
148
+ #:uri => "antlib:org.apache.ivy.ant",
149
+ })
150
+ end
151
+ end
152
+
153
+ task :deps => "ivy:install" do
154
+ puts("\n--> Installing dependencies")
155
+
156
+ dependencies = File.exists?(CUSTOM_DEPENDENCIES) ? eval(File.read(CUSTOM_DEPENDENCIES)) : DEFAULT_DEPENDENCIES
157
+ ant.configure :file => File.exists?(CUSTOM_IVY_SETTINGS) ? CUSTOM_IVY_SETTINGS : DEFAULT_IVY_SETTINGS
158
+
159
+ dependencies[:storm_artifacts].each do |dependency|
160
+ artifact, transitive = dependency.split(/\s*,\s*/)
161
+ ivy_retrieve(*artifact.split(':').concat([transitive.split(/\s*=\s*/).last, "#{TARGET_DEPENDENCY_DIR}/storm", "default"]))
162
+ end
163
+
164
+ dependencies[:topology_artifacts].each do |dependency|
165
+ artifact, transitive = dependency.split(/\s*,\s*/)
166
+ ivy_retrieve(*artifact.split(':').concat([transitive.split(/\s*=\s*/).last, "#{TARGET_DEPENDENCY_DIR}/topology", "default"]))
167
+ end
168
+ end
169
+
170
+ task :jar, [:include_dir] => [:clean_jar] do |t, args|
171
+ puts("\n--> Generating JAR file #{TARGET_CLUSTER_JAR}")
172
+
173
+ ant.jar :destfile => TARGET_CLUSTER_JAR do
174
+ # rejar all topology jars
175
+ Dir["target/dependency/topology/default/*.jar"].each do |jar|
176
+ puts("Extracting #{jar}")
177
+ zipfileset :src => jar, :includes => "**/*"
178
+ end
179
+ fileset :dir => TARGET_DIR do
180
+ include :name => "gems/**"
181
+ end
182
+ fileset :dir => TARGET_CLASSES_DIR
183
+ # red_storm.rb and red_storm/* must be in root of jar so that "require 'red_storm'"
184
+ # in bolts/spouts works in jar context
185
+ fileset :dir => TARGET_LIB_DIR do
186
+ exclude :name => "tasks/**"
187
+ end
188
+ if args[:include_dir]
189
+ dirs = args[:include_dir].split(":")
190
+
191
+ # first add any resources/ dir in the tree in the jar root - requirement for ShellBolt multilang resources
192
+ dirs.each do |dir|
193
+ resources_dirs = Dir.glob("#{dir}/**/resources")
194
+ resources_dirs.each do |resources_dir|
195
+ resources_parent = resources_dir.gsub("/resources", "")
196
+ fileset :dir => resources_parent do
197
+ include :name => "resources/**/*"
198
+ end
199
+ end
200
+ end
201
+
202
+ # include complete source dir tree (note we don't care about potential duplicated resources dir)
203
+ fileset :dir => CWD do
204
+ dirs.each{|dir| include :name => "#{dir}/**/*"}
205
+ end
206
+ end
207
+ manifest do
208
+ attribute :name => "Main-Class", :value => "redstorm.TopologyLauncher"
209
+ end
210
+ end
211
+ puts("\nRedStorm generated JAR file #{TARGET_CLUSTER_JAR}")
212
+ end
213
+
214
+ def build_java_dir(source_folder)
215
+ puts("\n--> Compiling Java")
216
+ ant.javac(
217
+ :srcdir => source_folder,
218
+ :destdir => TARGET_CLASSES_DIR,
219
+ :classpathref => 'classpath',
220
+ :source => "1.6",
221
+ :target => "1.6",
222
+ :debug => "yes",
223
+ :includeantruntime => "no",
224
+ :verbose => false,
225
+ :listfiles => true
226
+ ) do
227
+ # compilerarg :value => "-Xlint:unchecked"
228
+ end
229
+ end
230
+
231
+ def build_jruby(source_path)
232
+ puts("\n--> Compiling JRuby")
233
+ Dir.chdir(RedStorm::REDSTORM_HOME) do
234
+ argv = []
235
+ argv << '-t' << TARGET_SRC_DIR
236
+ argv << '--verbose'
237
+ argv << '--java'
238
+ Dir["#{TARGET_DEPENDENCY_DIR}/storm/default/*.jar"].each do |jar|
239
+ argv << '-c' << %("#{jar}")
240
+ end
241
+ argv << '-c' << %("#{TARGET_CLASSES_DIR}")
242
+ argv << source_path
243
+ status = JRuby::Compiler::compile_argv(argv)
244
+ end
245
+ end
246
+
247
+ def truefalse(s)
248
+ return true if s.to_s.downcase =~ /1|yes|true/
249
+ return false if s.to_s.downcase =~ /0|no|false/
250
+ nil
251
+ end
252
+
253
+ def ivy_retrieve(org, mod, rev, transitive, dir, conf)
254
+ ant.resolve({
255
+ :organisation => org,
256
+ :module => mod,
257
+ :revision => rev,
258
+ :inline => true,
259
+ :transitive => truefalse(transitive),
260
+ :conf => conf,
261
+ })
262
+
263
+ ant.retrieve({
264
+ :organisation => org,
265
+ :module => mod,
266
+ :revision => rev,
267
+ :pattern => "#{dir}/[conf]/[artifact]-[revision].[ext]",
268
+ :inline => true,
269
+ :transitive => truefalse(transitive),
270
+ :conf => conf,
271
+ })
272
+ end
@@ -0,0 +1,89 @@
1
+ package redstorm.storm.jruby;
2
+
3
+ import storm.trident.operation.TridentCollector;
4
+ import backtype.storm.task.TopologyContext;
5
+ import storm.trident.spout.IBatchSpout;
6
+ import backtype.storm.topology.OutputFieldsDeclarer;
7
+ import backtype.storm.tuple.Tuple;
8
+ import backtype.storm.tuple.Fields;
9
+ import java.util.Map;
10
+
11
+ /**
12
+ * the JRubyBatchSpout class is a simple proxy class to the actual spout implementation in JRuby.
13
+ * this proxy is required to bypass the serialization/deserialization process when dispatching
14
+ * the spout to the workers. JRuby does not yet support serialization from Java
15
+ * (Java serialization call on a JRuby class).
16
+ *
17
+ * Note that the JRuby spout proxy class is instanciated in the open method which is called after
18
+ * deserialization at the worker and in both the declareOutputFields and isDistributed methods which
19
+ * are called once before serialization at topology creation.
20
+ */
21
+ public class JRubyBatchSpout implements IBatchSpout {
22
+ IBatchSpout _proxySpout;
23
+ String _realSpoutClassName;
24
+ String _baseClassPath;
25
+ String[] _fields;
26
+
27
+ /**
28
+ * create a new JRubyBatchSpout
29
+ *
30
+ * @param baseClassPath the topology/project base JRuby class file path
31
+ * @param realSpoutClassName the fully qualified JRuby spout implementation class name
32
+ */
33
+ public JRubyBatchSpout(String baseClassPath, String realSpoutClassName, String[] fields) {
34
+ _baseClassPath = baseClassPath;
35
+ _realSpoutClassName = realSpoutClassName;
36
+ _fields = fields;
37
+ }
38
+
39
+ @Override
40
+ public void open(final Map conf, final TopologyContext context) {
41
+ // create instance of the jruby proxy class here, after deserialization in the workers.
42
+ _proxySpout = newProxySpout(_baseClassPath, _realSpoutClassName);
43
+ _proxySpout.open(conf, context);
44
+ }
45
+
46
+ @Override
47
+ public void emitBatch(final long batchId, final TridentCollector collector) {
48
+ _proxySpout.emitBatch(batchId, collector);
49
+ }
50
+
51
+
52
+ @Override
53
+ public void close() {
54
+ _proxySpout.close();
55
+ }
56
+
57
+ @Override
58
+ public void ack(final long batchId) {
59
+ _proxySpout.ack(batchId);
60
+ }
61
+
62
+ @Override
63
+ public Fields getOutputFields() {
64
+ // getOutputFields is executed in the topology creation time before serialisation.
65
+ // do not set the _proxySpout instance variable here to avoid JRuby serialization
66
+ // issues. Just create tmp spout instance to call declareOutputFields.
67
+ IBatchSpout spout = newProxySpout(_baseClassPath, _realSpoutClassName);
68
+ return spout.getOutputFields();
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 _proxySpout instance variable here to avoid JRuby serialization
75
+ // issues. Just create tmp spout instance to call declareOutputFields.
76
+ IBatchSpout spout = newProxySpout(_baseClassPath, _realSpoutClassName);
77
+ return spout.getComponentConfiguration();
78
+ }
79
+
80
+ private static IBatchSpout newProxySpout(String baseClassPath, String realSpoutClassName) {
81
+ try {
82
+ redstorm.proxy.BatchSpout proxy = new redstorm.proxy.BatchSpout(baseClassPath, realSpoutClassName);
83
+ return proxy;
84
+ }
85
+ catch (Exception e) {
86
+ throw new RuntimeException(e);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,88 @@
1
+ package redstorm.storm.jruby;
2
+
3
+ import backtype.storm.task.OutputCollector;
4
+ import backtype.storm.task.TopologyContext;
5
+ import backtype.storm.topology.IRichBolt;
6
+ import backtype.storm.topology.OutputFieldsDeclarer;
7
+ import backtype.storm.tuple.Tuple;
8
+ import backtype.storm.tuple.Fields;
9
+ import java.util.Map;
10
+
11
+ /**
12
+ * the JRubyBolt class is a simple proxy class to the actual bolt implementation in JRuby.
13
+ * this proxy is required to bypass the serialization/deserialization process when dispatching
14
+ * the bolts to the workers. JRuby does not yet support serialization from Java
15
+ * (Java serialization call on a JRuby class).
16
+ *
17
+ * Note that the JRuby bolt proxy class is instanciated in the prepare method which is called after
18
+ * deserialization at the worker and in the declareOutputFields method which is called once before
19
+ * serialization at topology creation.
20
+ */
21
+ public class JRubyBolt implements IRichBolt {
22
+ IRichBolt _proxyBolt;
23
+ String _realBoltClassName;
24
+ String _baseClassPath;
25
+ String[] _fields;
26
+
27
+ /**
28
+ * create a new JRubyBolt
29
+ *
30
+ * @param baseClassPath the topology/project base JRuby class file path
31
+ * @param realBoltClassName the fully qualified JRuby bolt implementation class name
32
+ */
33
+ public JRubyBolt(String baseClassPath, String realBoltClassName, String[] fields) {
34
+ _baseClassPath = baseClassPath;
35
+ _realBoltClassName = realBoltClassName;
36
+ _fields = fields;
37
+ }
38
+
39
+ @Override
40
+ public void prepare(final Map stormConf, final TopologyContext context, final OutputCollector collector) {
41
+ // create instance of the jruby class here, after deserialization in the workers.
42
+ _proxyBolt = newProxyBolt(_baseClassPath, _realBoltClassName);
43
+ _proxyBolt.prepare(stormConf, context, collector);
44
+ }
45
+
46
+ @Override
47
+ public void execute(Tuple input) {
48
+ _proxyBolt.execute(input);
49
+ }
50
+
51
+ @Override
52
+ public void cleanup() {
53
+ _proxyBolt.cleanup();
54
+ }
55
+
56
+ @Override
57
+ public void declareOutputFields(OutputFieldsDeclarer declarer) {
58
+ // declareOutputFields is executed in the topology creation time, before serialisation.
59
+ // do not set the _proxyBolt instance variable here to avoid JRuby serialization
60
+ // issues. Just create tmp bolt instance to call declareOutputFields.
61
+ if (_fields.length > 0) {
62
+ declarer.declare(new Fields(_fields));
63
+ } else {
64
+ IRichBolt bolt = newProxyBolt(_baseClassPath, _realBoltClassName);
65
+ bolt.declareOutputFields(declarer);
66
+ }
67
+ }
68
+
69
+ @Override
70
+ public Map<String, Object> getComponentConfiguration() {
71
+ // getComponentConfiguration is executed in the topology creation time, before serialisation.
72
+ // do not set the _proxyBolt instance variable here to avoid JRuby serialization
73
+ // issues. Just create tmp bolt instance to call declareOutputFields.
74
+ IRichBolt bolt = newProxyBolt(_baseClassPath, _realBoltClassName);
75
+ return bolt.getComponentConfiguration();
76
+ }
77
+
78
+
79
+ private static IRichBolt newProxyBolt(String baseClassPath, String realBoltClassName) {
80
+ try {
81
+ redstorm.proxy.Bolt proxy = new redstorm.proxy.Bolt(baseClassPath, realBoltClassName);
82
+ return proxy;
83
+ }
84
+ catch (Exception e) {
85
+ throw new RuntimeException(e);
86
+ }
87
+ }
88
+ }