kb-redstorm 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
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
+ }