redstorm 0.6.4 → 0.6.5
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.
- 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
|
+
}
|