redstorm 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -0
- data/README.md +206 -103
- data/examples/native/cluster_word_count_topology.rb +5 -5
- data/examples/native/local_exclamation_topology.rb +8 -8
- data/examples/native/local_exclamation_topology2.rb +7 -7
- data/examples/native/local_redis_word_count_topology.rb +7 -8
- data/examples/native/local_word_count_topology.rb +5 -5
- data/examples/simple/exclamation_topology.rb +7 -11
- data/examples/simple/exclamation_topology2.rb +10 -12
- data/examples/simple/hello_world_topology.rb +22 -0
- data/examples/simple/kafka_topology.rb +2 -1
- data/examples/simple/redis_word_count_topology.rb +3 -5
- data/examples/simple/ruby_version_topology.rb +7 -1
- data/examples/simple/word_count_topology.rb +8 -10
- data/ivy/settings.xml +1 -0
- data/ivy/storm_dependencies.xml +8 -0
- data/ivy/topology_dependencies.xml +7 -0
- data/lib/red_storm.rb +1 -0
- data/lib/red_storm/application.rb +9 -7
- data/lib/red_storm/configurator.rb +1 -1
- data/lib/red_storm/proxy/batch_bolt.rb +63 -0
- data/lib/red_storm/proxy/batch_committer_bolt.rb +52 -0
- data/lib/red_storm/proxy/batch_spout.rb +59 -0
- data/lib/red_storm/proxy/proxy_function.rb +40 -0
- data/lib/red_storm/proxy/transactional_committer_spout.rb +47 -0
- data/lib/red_storm/proxy/transactional_spout.rb +46 -0
- data/lib/red_storm/simple_drpc_topology.rb +87 -0
- data/lib/red_storm/simple_topology.rb +14 -4
- data/lib/red_storm/topology_launcher.rb +22 -3
- data/lib/red_storm/version.rb +1 -1
- data/lib/tasks/red_storm.rake +66 -104
- data/redstorm.gemspec +24 -0
- data/src/main/redstorm/storm/jruby/JRubyBatchBolt.java +90 -0
- data/src/main/redstorm/storm/jruby/JRubyBatchCommitterBolt.java +9 -0
- data/src/main/redstorm/storm/jruby/JRubyBatchSpout.java +88 -0
- data/src/main/redstorm/storm/jruby/JRubyProxyFunction.java +51 -0
- data/src/main/redstorm/storm/jruby/JRubyShellSpout.java +1 -1
- data/src/main/redstorm/storm/jruby/JRubyTransactionalBolt.java +90 -0
- data/src/main/redstorm/storm/jruby/JRubyTransactionalCommitterBolt.java +31 -0
- data/src/main/redstorm/storm/jruby/JRubyTransactionalCommitterSpout.java +44 -0
- data/src/main/redstorm/storm/jruby/JRubyTransactionalSpout.java +89 -0
- metadata +35 -14
- 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 }
|
data/lib/red_storm/version.rb
CHANGED
data/lib/tasks/red_storm.rake
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
begin
|
2
2
|
require 'ant'
|
3
3
|
rescue
|
4
|
-
puts("
|
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
|
-
|
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
|
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
|
37
|
+
ant.delete 'dir' => TARGET_DIR
|
49
38
|
end
|
50
39
|
|
51
40
|
task :clean_jar do
|
52
|
-
ant.delete
|
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
|
58
|
-
ant.mkdir
|
59
|
-
ant.mkdir
|
60
|
-
ant.mkdir
|
61
|
-
ant.mkdir
|
62
|
-
ant.mkdir
|
63
|
-
ant.path
|
64
|
-
fileset
|
65
|
-
fileset
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
134
|
-
|
135
|
-
|
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
|
141
|
-
fileset
|
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
|
-
|
146
|
-
|
147
|
-
|
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
|
-
|
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
|
-
|
159
|
-
|
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
|
-
|
164
|
-
|
165
|
-
|
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
|
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
|
165
|
+
zipfileset 'src' => jar, 'includes' => "**/*"
|
177
166
|
end
|
178
|
-
fileset
|
179
|
-
include
|
167
|
+
fileset 'dir' => TARGET_DIR do
|
168
|
+
include 'name' => "gems/**"
|
180
169
|
end
|
181
|
-
fileset
|
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
|
185
|
-
exclude
|
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
|
196
|
-
include
|
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
|
203
|
-
dirs.each{|dir| include
|
191
|
+
fileset 'dir' => CWD do
|
192
|
+
dirs.each{|dir| include 'name' => "#{dir}/**/*"}
|
204
193
|
end
|
205
194
|
end
|
206
195
|
manifest do
|
207
|
-
attribute
|
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
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
data/redstorm.gemspec
ADDED
@@ -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
|
+
}
|