norikra 1.2.1-java → 1.2.2-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e2938132b83a49bb328d060517750c5cb9d7e95
4
- data.tar.gz: 7c20e09c3795b209946f08f49d3503ccccec3caf
3
+ metadata.gz: fa80888abaaa606aa96b77fc3e1e33b17f8bb098
4
+ data.tar.gz: 423c64919bae627115f30f37ac6750883a534676
5
5
  SHA512:
6
- metadata.gz: 6a684145944825a6c813ec8695a7eee3ee6411de5654af120a90a77f7ee4e0fae9becef6535c476b5afce4754a7923d9188a8feca8c912a0c55393f2a6989794
7
- data.tar.gz: 4140d210916fcb7d575527fce40f9b3bda7d7fc3a9f7af9d88b2ef1c6202678d63b28c7369f71d227df399548d708486ccfea5aca2b7bfeb6f771acfda88e773
6
+ metadata.gz: 9981e141e6d99f2cb9a793629a6f0c46db0df1f8df8661e2fe6bfbddabc49fb946da8b839cd0b91352c09a6816340a1078b99d7211f29f90e706517b3576c31e
7
+ data.tar.gz: 755251d7e8fe172c7f72e8cebb37ecfdea10937de3f39c36300651647efa8ad1423ff7fd953e65392e794a0daf227e1312a8f3cbcb50cfb4d96b37e8db155191
data/Changes.md CHANGED
@@ -3,6 +3,8 @@
3
3
  Changes of norikra.
4
4
 
5
5
  ## v1
6
+ * v1.2.2
7
+ * Change API for custom listner plugins (incompatible with 1.2.0, 1.2.1)
6
8
  * v1.2.1
7
9
  * Fix bug to fail to rewrite nullable fields
8
10
  * v1.2.0
@@ -45,7 +45,7 @@ module Norikra
45
45
 
46
46
  @waiting_queries = []
47
47
 
48
- @listeners = []
48
+ @listeners = {} # Listener.label => Listener
49
49
  @running_listeners = {} # query_name => listener
50
50
  end
51
51
 
@@ -373,7 +373,7 @@ module Norikra
373
373
 
374
374
  def register_query(query)
375
375
 
376
- if lo_target_name = Norikra::Listener::Loopback.check(query.group)
376
+ if lo_target_name = Norikra::Listener::Loopback.target(query.group)
377
377
  raise "Invalid loopback target name should be checked before. THIS IS BUG." unless Norikra::Target.valid?(lo_target_name)
378
378
 
379
379
  target = Norikra::Target.new(lo_target_name)
@@ -388,7 +388,7 @@ module Norikra
388
388
  if reason = query.invalid?
389
389
  raise Norikra::ClientError, "invalid query '#{query.name}': #{reason}"
390
390
  end
391
- if lo_target_name = Norikra::Listener::Loopback.check(query.group)
391
+ if lo_target_name = Norikra::Listener::Loopback.target(query.group)
392
392
  raise Norikra::ClientError, "loopback target '#{lo_target_name}'" unless Norikra::Target.valid?(lo_target_name)
393
393
  end
394
394
 
@@ -520,8 +520,29 @@ module Norikra
520
520
  end
521
521
  end
522
522
 
523
- def load_listener(listener_klass)
524
- @listeners.push(listener_klass)
523
+ def load_listener(klass)
524
+ @listeners[klass.label] = klass
525
+ klass
526
+ end
527
+
528
+ def create_listener(query)
529
+ opts = Norikra::Listener.parse(query.group)
530
+ klass = if opts && @listeners.has_key?(opts[:name])
531
+ @listeners[opts[:name]]
532
+ else
533
+ Norikra::Listener::MemoryPool
534
+ end
535
+ argument = opts ? opts[:argument] : nil
536
+ trace("selecting listeners"){ { group: query.group, listener: klass, argument: argument } }
537
+
538
+ inst = klass.new(argument, query.name, query.group)
539
+ inst.events_statistics = @statistics[:events]
540
+
541
+ inst.engine = self if inst.respond_to?(:engine=)
542
+ inst.output_pool = @output_pool if inst.respond_to?(:output_pool=)
543
+
544
+ inst.start
545
+ inst
525
546
  end
526
547
 
527
548
  # this method should be protected with @mutex lock
@@ -537,19 +558,7 @@ module Norikra
537
558
  statement_model = administrator.compileEPL(query.expression)
538
559
  Norikra::Query.rewrite_query(statement_model, event_type_name_map)
539
560
 
540
- listener = nil
541
- @listeners.each do |klass|
542
- trace("checking listeners"){ {target: klass, result: klass.check(query.group)} }
543
- if klass.check(query.group)
544
- listener = klass.new(query.name, query.group, @statistics[:events])
545
- break
546
- end
547
- end
548
- raise "BUG: no listener is selected" unless listener
549
- listener.engine = self if listener.respond_to?(:engine=)
550
- listener.output_pool = @output_pool if listener.respond_to?(:output_pool=)
551
- listener.start
552
- @running_listeners[query.name] = listener
561
+ @running_listeners[query.name] = listener = create_listener(query)
553
562
 
554
563
  epl = administrator.create(statement_model)
555
564
  epl.java_send :addListener, [com.espertech.esper.client.UpdateListener.java_class], listener
@@ -16,6 +16,14 @@ require 'json'
16
16
 
17
17
  module Norikra
18
18
  module Listener
19
+ def self.parse(group_name)
20
+ if group_name && group_name =~ /^([_A-Z]+)\((.*)\)$/
21
+ {name: $1, argument: $2}
22
+ else
23
+ nil
24
+ end
25
+ end
26
+
19
27
  def self.listup
20
28
  return unless defined? Gem
21
29
 
@@ -41,7 +49,7 @@ module Norikra
41
49
  end
42
50
 
43
51
  known_consts = [:Base, :MemoryPool, :Loopback, :Stdout]
44
- listeners = [Norikra::Listener::Stdout, Norikra::Listener::Loopback]
52
+ listeners = []
45
53
  self.constants.each do |c|
46
54
  next if known_consts.include?(c)
47
55
 
@@ -50,7 +58,9 @@ module Norikra
50
58
  listeners.push(klass)
51
59
  end
52
60
  end
53
- listeners.push(Norikra::Listener::MemoryPool)
61
+ [Norikra::Listener::Stdout, Norikra::Listener::Loopback].each do |listener|
62
+ listeners.push(listener)
63
+ end
54
64
  listeners
55
65
  end
56
66
 
@@ -59,33 +69,37 @@ module Norikra
59
69
 
60
70
  DEFAULT_ASYNC_INTERVAL = 0.1
61
71
 
62
- def self.check(group_name)
72
+ attr_writer :events_statistics
73
+ # attr_writer :engine
74
+ # attr_writer :output_pool
75
+
76
+ def self.label
63
77
  raise NotImplementedError
64
78
  end
65
79
 
66
- def initialize(query_name, query_group, events_statistics)
80
+ def initialize(argument, query_name, query_group)
81
+ @argument = argument
67
82
  @query_name = query_name
68
83
  @query_group = query_group
69
- @events_statistics = events_statistics
70
84
 
71
85
  @async_interval = DEFAULT_ASYNC_INTERVAL
72
86
 
87
+ @mode = if self.respond_to?(:process_sync)
88
+ :sync
89
+ elsif self.respond_to?(:process_async)
90
+ :async
91
+ else
92
+ raise "BUG: Invalid custom listener '#{self.class.to_s}'"
93
+ end
94
+
73
95
  @thread = nil
74
96
  @events = []
75
97
  @mutex = Mutex.new
76
98
  @running = true
77
99
  end
78
100
 
79
- # def engine=(engine)
80
- # @engine = engine
81
- # end
82
-
83
- # def output_pool=(output_pool)
84
- # @output_pool = output_pool
85
- # end
86
-
87
101
  def start
88
- if self.respond_to?(:process_async)
102
+ if @mode == :async
89
103
  trace "starting thread to process events in background", query: @query_name
90
104
  @thread = Thread.new(&method(:background))
91
105
  end
@@ -117,9 +131,6 @@ module Norikra
117
131
  end
118
132
  end
119
133
 
120
- # def process_async
121
- # end
122
-
123
134
  def shutdown
124
135
  trace "stopping listener", query: @query_name
125
136
  @running = false
@@ -149,74 +160,88 @@ module Norikra
149
160
 
150
161
  def update(new_events, old_events)
151
162
  t = Time.now.to_i
152
- events = new_events.map{|e| [t, type_convert(e)]}
153
- trace("updated event"){ { query: @query_name, group: @query_group, event: events } }
154
- push(events)
155
- @events_statistics[:output] += events.size
163
+ if @mode == :sync
164
+ news = new_events.map{|e| type_convert(e) }
165
+ olds = if old_events.respond_to?(:map)
166
+ old_events.map{|e| type_convert(e) }
167
+ else
168
+ type_convert(old_events)
169
+ end
170
+ trace("produced events"){ { listener: self.class, query: @query_name, group: @query_group, news: news, olds: olds } }
171
+ process_sync(news, olds)
172
+ @events_statistics[:output] += news.size
173
+ else # async
174
+ events = new_events.map{|e| [t, type_convert(e)]}
175
+ trace("pushed events"){ { listener: self.class, query: @query_name, group: @query_group, event: events } }
176
+ push(events)
177
+ @events_statistics[:output] += events.size
178
+ end
156
179
  end
157
180
  end
158
181
 
159
182
  class MemoryPool < Base
160
- def self.check(group_name)
161
- true
162
- end
183
+ attr_writer :output_pool
163
184
 
164
- def output_pool=(output_pool)
165
- @output_pool = output_pool
185
+ def self.label
186
+ nil # Memory pool listener is built-in and implicit listener
166
187
  end
167
188
 
168
- def update(new_events, old_events)
189
+ def process_sync(news, olds)
169
190
  t = Time.now.to_i
170
- events = new_events.map{|e| [t, type_convert(e)]}
171
- trace("updated event"){ { query: @query_name, group: @query_group, event: events } }
191
+ events = news.map{|e| [t, e]}
172
192
  @output_pool.push(@query_name, @query_group, events)
173
- @events_statistics[:output] += events.size
174
193
  end
175
194
  end
176
195
 
177
196
  class Loopback < Base
178
- def self.check(group_name)
179
- group_name && group_name =~ /^LOOPBACK\((.+)\)$/ && $1
197
+ attr_writer :engine
198
+
199
+ def self.label
200
+ "LOOPBACK"
180
201
  end
181
202
 
182
- def initialize(query_name, query_group, events_statistics)
183
- super
184
- @loopback_target = Loopback.check(query_group)
185
- raise "BUG: query group is not 'LOOPBACK(...)'" unless @loopback_target
203
+ def self.target(query_group)
204
+ if query_group
205
+ opts = Norikra::Listener.parse(query_group)
206
+ if opts && opts[:name] == label()
207
+ opts[:argument]
208
+ else
209
+ nil
210
+ end
211
+ else
212
+ nil
213
+ end
186
214
  end
187
215
 
188
- def engine=(engine)
189
- @engine = engine
216
+ def initialize(argument, query_name, query_group)
217
+ super
218
+ if @argument.nil? || @argument.empty?
219
+ raise Norikra::ClientError, "LOOPBACK target name not specified"
220
+ end
190
221
  end
191
222
 
192
- def update(new_events, old_events)
193
- event_list = new_events.map{|e| type_convert(e) }
194
- trace("loopback event"){ { query: @query_name, group: @query_group, event: event_list } }
195
- @events_statistics[:output] += event_list.size
196
- #
223
+ def process_sync(news, olds)
197
224
  # We does NOT convert 'container.$0' into container['field'].
198
225
  # Use escaped names like 'container__0'. That is NOT so confused.
199
- @engine.send(@loopback_target, event_list)
226
+ trace("loopback event"){ { query: @query_name, group: @query_group, event: news } }
227
+ @engine.send(@argument, news)
200
228
  end
201
229
  end
202
230
 
203
231
  class Stdout < Base
204
- def self.check(group_name)
205
- group_name && group_name == "STDOUT()"
232
+ attr_accessor :stdout
233
+
234
+ def self.label
235
+ "STDOUT"
206
236
  end
207
237
 
208
- def initialize(query_name, query_group, events_statistics)
238
+ def initialize(argument, query_name, query_group)
209
239
  super
210
- raise "BUG: query group is not 'STDOUT()'" unless Stdout.check(query_group)
211
240
  @stdout = STDOUT
212
241
  end
213
242
 
214
- def update(new_events, old_events)
215
- event_list = new_events.map{|e| type_convert(e) }
216
- trace("stdout event"){ { query: @query_name, event: event_list } }
217
- @events_statistics[:output] += event_list.size
218
-
219
- event_list.each do |e|
243
+ def process_sync(news, olds)
244
+ news.each do |e|
220
245
  @stdout.puts @query_name + "\t" + JSON.dump(e)
221
246
  end
222
247
  end
@@ -0,0 +1,35 @@
1
+ module Norikra
2
+ module ListenerSpecHelper
3
+
4
+ ### TODO: more util methods?
5
+ # utilities w/ #start, #shutdown ?
6
+ # utilities to produce dummy output events ?
7
+
8
+ class DummyEngine
9
+ attr_reader :events
10
+
11
+ def initialize
12
+ @events = {}
13
+ end
14
+
15
+ def send(target, events)
16
+ @events[target] ||= []
17
+ @events[target].push(*events)
18
+ end
19
+ end
20
+
21
+ class DummyOutputPool
22
+ attr_reader :pool
23
+
24
+ def initialize
25
+ @pool = {}
26
+ end
27
+
28
+ def push(query_name, query_group, events)
29
+ @pool[query_group] ||= {}
30
+ @pool[query_group][query_name] ||= []
31
+ @pool[query_group][query_name].push(*events)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module Norikra
2
- VERSION = "1.2.1"
2
+ VERSION = "1.2.2"
3
3
  end
@@ -1,45 +1,26 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require_relative './spec_helper'
3
-
4
3
  require 'json'
5
4
  require 'norikra/listener'
5
+ require 'norikra/listener_spec_helper'
6
6
 
7
- class DummyEngine
8
- attr_reader :events
9
-
10
- def initialize
11
- @events = {}
12
- end
13
-
14
- def send(target, events)
15
- @events[target] ||= []
16
- @events[target].push(*events)
7
+ class DummySyncListener < Norikra::Listener::Base
8
+ def process_sync(news, olds)
9
+ # drop
17
10
  end
18
11
  end
19
12
 
20
- class DummyOutputPool
21
- attr_reader :pool
22
-
23
- def initialize
24
- @pool = {}
25
- end
26
-
27
- def push(query_name, query_group, events)
28
- @pool[query_group] ||= {}
29
- @pool[query_group][query_name] ||= []
30
- @pool[query_group][query_name].push(*events)
13
+ class DummyAsyncListener < Norikra::Listener::Base
14
+ def process_async(news, olds)
15
+ # drop
31
16
  end
32
17
  end
33
18
 
34
19
  describe Norikra::Listener::Base do
35
- it 'should be initialized' do
36
- statistics = {output: 0}
37
- expect { Norikra::Listener::Base.new('name', 'group', statistics) }.not_to raise_error
38
- end
39
-
40
20
  describe '#type_convert' do
41
21
  statistics = {output: 0}
42
- listener = Norikra::Listener::Base.new('name', 'group', statistics)
22
+ listener = DummySyncListener.new('', 'name', 'group')
23
+ listener.events_statistics = statistics
43
24
 
44
25
  it 'returns value itself for number, boolean and nil' do
45
26
  val = 10001
@@ -115,103 +96,77 @@ describe Norikra::Listener::Base do
115
96
  end
116
97
  end
117
98
 
118
- ### TODO: add specs of #start, #process_async, #push and default #update
119
- ### TODO: add norikra/listener_spec_helper.rb
99
+ ### TODO: add specs of .parse, #start, #shutdown, #push and #update
120
100
  end
121
101
 
122
102
  describe Norikra::Listener::MemoryPool do
123
- describe '.check' do
124
- it 'always returns true' do
125
- expect(Norikra::Listener::MemoryPool.check(nil)).to be_truthy
126
- expect(Norikra::Listener::MemoryPool.check('')).to be_truthy
127
- expect(Norikra::Listener::MemoryPool.check('FOO')).to be_truthy
128
- expect(Norikra::Listener::MemoryPool.check('FOO()')).to be_truthy
103
+ describe '.label' do
104
+ it 'returns nil' do
105
+ expect(Norikra::Listener::MemoryPool.label).to be_nil
129
106
  end
130
107
  end
131
108
 
132
- describe '#update' do
133
- statistics = {output: 0}
134
- listener = Norikra::Listener::MemoryPool.new('name', 'group', statistics)
135
- listener.output_pool = dummy_pool = DummyOutputPool.new
109
+ describe '#process_sync' do
110
+ listener = Norikra::Listener::MemoryPool.new(nil, 'name', 'group')
111
+ listener.output_pool = dummy_pool = Norikra::ListenerSpecHelper::DummyOutputPool.new
136
112
 
137
113
  it 'pushs events into pool, with current time' do
138
- listener.update([{"n1" => 100, "s" => "string one"}, {"n1" => 101, "s" => "string two"}], [])
139
- expect(statistics[:output]).to eql(2)
114
+ listener.process_sync([{"n1" => 100, "s" => "string one"}, {"n1" => 101, "s" => "string two"}], [])
140
115
  expect(dummy_pool.pool['group']['name'].size).to eql(2)
141
116
  expect(dummy_pool.pool['group']['name'][0][0]).to be_a(Fixnum)
142
117
  expect(dummy_pool.pool['group']['name'][0][1]).to eql({"n1" => 100, "s" => "string one"})
143
118
  expect(dummy_pool.pool['group']['name'][1][1]).to eql({"n1" => 101, "s" => "string two"})
144
119
 
145
- listener.update([{"n1" => 102, "s" => "string three"}], [])
146
- expect(statistics[:output]).to eql(3)
120
+ listener.process_sync([{"n1" => 102, "s" => "string three"}], [])
147
121
  expect(dummy_pool.pool['group']['name'].size).to eql(3)
148
122
  end
149
123
  end
150
124
  end
151
125
 
152
126
  describe Norikra::Listener::Loopback do
153
- describe '.check' do
154
- it 'returns nil for nil group' do
155
- expect(Norikra::Listener::Loopback.check(nil)).to be_nil
156
- end
157
-
158
- it 'returns nil for string group name without prefix' do
159
- expect(Norikra::Listener::Loopback.check('a')).to be_nil
160
- expect(Norikra::Listener::Loopback.check('group1')).to be_nil
161
- expect(Norikra::Listener::Loopback.check('LOOPBACK')).to be_nil
162
- end
163
-
164
- it 'returns specified string as loopback target by parentheses' do
165
- expect(Norikra::Listener::Loopback.check('LOOPBACK()')).to be_nil
166
- expect(Norikra::Listener::Loopback.check('LOOPBACK(a)')).to eql('a')
167
- expect(Norikra::Listener::Loopback.check('LOOPBACK(loopback_target)')).to eql('loopback_target')
168
- expect(Norikra::Listener::Loopback.check('LOOPBACK(target name)')).to eql('target name') # should be invalid on 'open'
127
+ describe '.label' do
128
+ it 'returns "LOOPBACK"' do
129
+ expect(Norikra::Listener::Loopback.label).to eql("LOOPBACK")
169
130
  end
170
131
  end
171
132
 
172
133
  it 'should be initialized' do
173
134
  statistics = {output: 0}
174
- expect { Norikra::Listener::Loopback.new('name', 'LOOPBACK(target1)', statistics) }.not_to raise_error
135
+ inst = Norikra::Listener::Loopback.new('target1', 'name', 'LOOPBACK(target1)')
136
+ inst.events_statistics = statistics
175
137
  end
176
138
 
177
- describe '#update' do
178
- statistics = {output: 0}
179
- listener = Norikra::Listener::Loopback.new('name', 'LOOPBACK(target1)', statistics)
180
- listener.engine = dummy_engine = DummyEngine.new
139
+ describe '#process_sync' do
140
+ listener = Norikra::Listener::Loopback.new('target1', 'name', 'LOOPBACK(target1)')
141
+ listener.engine = dummy_engine = Norikra::ListenerSpecHelper::DummyEngine.new
181
142
 
182
143
  it 'sends events into engine with target name' do
183
- listener.update([{"n1" => 100, "s" => "string one"}, {"n1" => 101, "s" => "string two"}], [])
184
- expect(statistics[:output]).to eql(2)
144
+ listener.process_sync([{"n1" => 100, "s" => "string one"}, {"n1" => 101, "s" => "string two"}], [])
185
145
  expect(dummy_engine.events['target1'].size).to eql(2)
186
146
  expect(dummy_engine.events['target1'][0]).to eql({"n1" => 100, "s" => "string one"})
187
147
  expect(dummy_engine.events['target1'][1]).to eql({"n1" => 101, "s" => "string two"})
188
148
 
189
- listener.update([{"n1" => 102, "s" => "string three"}], [])
190
- expect(statistics[:output]).to eql(3)
149
+ listener.process_sync([{"n1" => 102, "s" => "string three"}], [])
191
150
  expect(dummy_engine.events['target1'].size).to eql(3)
192
151
  end
193
152
  end
194
153
  end
195
154
 
196
155
  describe Norikra::Listener::Stdout do
197
- describe '.check' do
198
- it 'returns true if group name is "STDOUT()"' do
199
- expect(Norikra::Listener::Stdout.check(nil)).to be_falsy
200
- expect(Norikra::Listener::Stdout.check("")).to be_falsy
201
- expect(Norikra::Listener::Stdout.check("foo")).to be_falsy
202
- expect(Norikra::Listener::Stdout.check("STDOUT")).to be_falsy
203
- expect(Norikra::Listener::Stdout.check("STDOUT()")).to be_truthy
156
+ describe '.label' do
157
+ it 'returns "STDOUT"' do
158
+ expect(Norikra::Listener::Stdout.label).to eql("STDOUT")
204
159
  end
205
160
  end
206
161
 
207
162
  it 'should be initialized' do
208
163
  statistics = {output: 0}
209
- expect { Norikra::Listener::Stdout.new('name', 'STDOUT()', statistics) }.not_to raise_error
164
+ inst = Norikra::Listener::Stdout.new('', 'name', 'STDOUT()')
165
+ inst.events_statistics = statistics
210
166
  end
211
167
 
212
- describe '#update' do
213
- statistics = {output: 0}
214
- listener = Norikra::Listener::Stdout.new('name', 'STDOUT()', statistics)
168
+ describe '#process_sync' do
169
+ listener = Norikra::Listener::Stdout.new('', 'name', 'STDOUT()')
215
170
  dummyio = StringIO.new
216
171
  listener.instance_eval{ @stdout = dummyio }
217
172
 
@@ -219,12 +174,10 @@ describe Norikra::Listener::Stdout do
219
174
  dummyio.truncate(0)
220
175
 
221
176
  events1 = [{"n1" => 100, "s" => "string one"}, {"n1" => 101, "s" => "string two"}]
222
- listener.update(events1, [])
223
- expect(statistics[:output]).to eql(2)
177
+ listener.process_sync(events1, [])
224
178
 
225
179
  events2 = [{"n1" => 102, "s" => "string three"}]
226
- listener.update(events2, [])
227
- expect(statistics[:output]).to eql(3)
180
+ listener.process_sync(events2, [])
228
181
 
229
182
  results = []
230
183
  dummyio.string.split("\n").each do |line|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: norikra
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  platform: java
6
6
  authors:
7
7
  - TAGOMORI Satoshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-16 00:00:00.000000000 Z
11
+ date: 2015-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mizuno
@@ -218,6 +218,7 @@ files:
218
218
  - lib/norikra/field.rb
219
219
  - lib/norikra/fieldset.rb
220
220
  - lib/norikra/listener.rb
221
+ - lib/norikra/listener_spec_helper.rb
221
222
  - lib/norikra/logger.rb
222
223
  - lib/norikra/logger_mizuno_patch.rb
223
224
  - lib/norikra/output_pool.rb