norikra 0.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE +339 -0
- data/README.md +104 -0
- data/Rakefile +10 -0
- data/bin/norikra +8 -0
- data/esper/changelog.txt +1066 -0
- data/esper/esper-4.9.0.jar +0 -0
- data/esper/esper-license.txt +95 -0
- data/esper/esper/lib/antlr-runtime-3.2.jar +0 -0
- data/esper/esper/lib/cglib-nodep-2.2.jar +0 -0
- data/esper/esper/lib/commons-logging-1.1.1.jar +0 -0
- data/esper/esper/lib/esper_3rdparties.license +299 -0
- data/esper/esper/lib/log4j-1.2.16.jar +0 -0
- data/esper/esper/lib/readme.txt +38 -0
- data/esper/esperio-amqp-4.9.0.jar +0 -0
- data/esper/esperio-amqp/lib/commons-cli-1.1.jar +0 -0
- data/esper/esperio-amqp/lib/commons-io-1.2.jar +0 -0
- data/esper/esperio-amqp/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-amqp/lib/esperio_amqp_jars.txt +2 -0
- data/esper/esperio-amqp/lib/rabbitmq-client.jar +0 -0
- data/esper/esperio-csv-4.9.0.jar +0 -0
- data/esper/esperio-csv/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-db-4.9.0.jar +0 -0
- data/esper/esperio-db/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-http-4.9.0.jar +0 -0
- data/esper/esperio-http/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-http/lib/httpclient-4.0.1.jar +0 -0
- data/esper/esperio-http/lib/httpcore-4.0.1.jar +0 -0
- data/esper/esperio-http/lib/httpcore-nio-4.0.1.jar +0 -0
- data/esper/esperio-license.txt +95 -0
- data/esper/esperio-socket-4.9.0.jar +0 -0
- data/esper/esperio-socket/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-springjms-4.9.0.jar +0 -0
- data/esper/esperio-springjms/lib/activation-1.1.jar +0 -0
- data/esper/esperio-springjms/lib/activemq-core-5.7.0.jar +0 -0
- data/esper/esperio-springjms/lib/activemq-pool-5.7.0.jar +0 -0
- data/esper/esperio-springjms/lib/commons-pool-1.6.jar +0 -0
- data/esper/esperio-springjms/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-springjms/lib/geronimo-j2ee-management_1.1_spec-1.0.1.jar +0 -0
- data/esper/esperio-springjms/lib/geronimo-jms_1.1_spec-1.1.1.jar +0 -0
- data/esper/esperio-springjms/lib/junit-4.8.2.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.asm-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.beans-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.context-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.core-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.expression-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.jms-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/org.springframework.transaction-3.1.1.RELEASE.jar +0 -0
- data/esper/esperio-springjms/lib/slf4j-api-1.7.2.jar +0 -0
- data/esper/esperio-springjms/lib/slf4j-log4j12-1.7.2.jar +0 -0
- data/esper/esperio-stax-4.9.0.jar +0 -0
- data/esper/esperio-stax/lib/axiom-api-1.2.9.jar +0 -0
- data/esper/esperio-stax/lib/axiom-c14n-1.2.9.jar +0 -0
- data/esper/esperio-stax/lib/axiom-dom-1.2.9.jar +0 -0
- data/esper/esperio-stax/lib/axiom-impl-1.2.9.jar +0 -0
- data/esper/esperio-stax/lib/commons-logging-1.1.1.jar +0 -0
- data/esper/esperio-stax/lib/commons-logging-LICENSE.txt +203 -0
- data/esper/esperio-stax/lib/esperio_3rdparties.license +1328 -0
- data/esper/esperio-stax/lib/geronimo-activation-LICENSE.txt +203 -0
- data/esper/esperio-stax/lib/geronimo-activation_1.1_spec-1.0.2.jar +0 -0
- data/esper/esperio-stax/lib/geronimo-javamail-LICENSE.txt +203 -0
- data/esper/esperio-stax/lib/geronimo-javamail_1.4_spec-1.6.jar +0 -0
- data/esper/esperio-stax/lib/geronimo-stax-api-LICENSE.txt +203 -0
- data/esper/esperio-stax/lib/geronimo-stax-api_1.0_spec-1.0.1.jar +0 -0
- data/esper/esperio-stax/lib/jaxen-1.1.1.jar +0 -0
- data/esper/esperio-stax/lib/jaxen-LICENSE.txt +33 -0
- data/esper/esperio-stax/lib/wstx-LICENSE.txt +203 -0
- data/esper/esperio-stax/lib/wstx-asl-3.2.9.jar +0 -0
- data/junks/esper-test.rb +79 -0
- data/junks/glassfish.rb +17 -0
- data/junks/mizuno.rb +28 -0
- data/junks/simple_test.rb +35 -0
- data/junks/type_confliction.rb +46 -0
- data/junks/type_conversion.rb +49 -0
- data/junks/type_inherit.rb +67 -0
- data/lib/norikra.rb +13 -0
- data/lib/norikra/cli.rb +24 -0
- data/lib/norikra/engine.rb +231 -0
- data/lib/norikra/output_pool.rb +45 -0
- data/lib/norikra/query.rb +173 -0
- data/lib/norikra/rpc.rb +6 -0
- data/lib/norikra/rpc/handler.rb +57 -0
- data/lib/norikra/rpc/http.rb +36 -0
- data/lib/norikra/server.rb +41 -0
- data/lib/norikra/typedef.rb +307 -0
- data/lib/norikra/typedef_manager.rb +91 -0
- data/lib/norikra/version.rb +3 -0
- data/norikra.gemspec +33 -0
- data/script/spec_server_pry +45 -0
- data/spec/field_spec.rb +141 -0
- data/spec/fieldset_spec.rb +172 -0
- data/spec/output_pool_spec.rb +75 -0
- data/spec/query_spec.rb +82 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/typedef_manager_spec.rb +128 -0
- data/spec/typedef_spec.rb +248 -0
- metadata +328 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
require 'norikra/query'
|
4
|
+
require 'norikra/output_pool'
|
5
|
+
require 'norikra/engine'
|
6
|
+
|
7
|
+
pool = Norikra::OutputPool.new
|
8
|
+
|
9
|
+
query1 = Norikra::Query.new(
|
10
|
+
:name => 'OrderEvent over 150 price counts per 10secs',
|
11
|
+
:tablename => 'OrderEvent',
|
12
|
+
:expression => 'select count(*) AS cnt from OrderEvent.win:time_batch(10 seconds) where price > 150'
|
13
|
+
)
|
14
|
+
query2 = Norikra::Query.new(
|
15
|
+
:name => 'OrderEvent events with 2 or more count',
|
16
|
+
:tablename => 'OrderEvent',
|
17
|
+
:expression => 'select * from OrderEvent where count > 1'
|
18
|
+
)
|
19
|
+
engine = Norikra::Engine.new(pool)
|
20
|
+
|
21
|
+
engine.register(query1)
|
22
|
+
engine.register(query2)
|
23
|
+
|
24
|
+
flag = true
|
25
|
+
|
26
|
+
thread = Thread.new do
|
27
|
+
while flag
|
28
|
+
sleep 1
|
29
|
+
results = pool.pop('OrderEvent over 150 price counts per 10secs')
|
30
|
+
pp(results) if results.size > 0
|
31
|
+
results = pool.pop('OrderEvent events with 2 or more count')
|
32
|
+
pp(results) if results.size > 0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
t = Time.now + 35
|
37
|
+
while Time.now < t
|
38
|
+
3.times do
|
39
|
+
engine.send('OrderEvent', [{"itemName"=>"test","price"=>150,"count"=>1}, {"itemName"=>"test","price"=>200,"count"=>1}])
|
40
|
+
sleep 3
|
41
|
+
end
|
42
|
+
engine.send('OrderEvent', [{"itemName"=>"test2","price"=>300}])
|
43
|
+
engine.send('OrderEvent', [{"itemName"=>"test2","price"=>300,"count"=>3000000000}])
|
44
|
+
engine.send('OrderEvent', [{"itemName"=>"test2","price"=>300,"count"=>3000}])
|
45
|
+
end
|
46
|
+
|
47
|
+
flag = false
|
48
|
+
thread.join
|
49
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
require 'java'
|
4
|
+
require 'esper/esper-4.9.0.jar'
|
5
|
+
require 'esper/esper/lib/commons-logging-1.1.1.jar'
|
6
|
+
require 'esper/esper/lib/antlr-runtime-3.2.jar'
|
7
|
+
require 'esper/esper/lib/cglib-nodep-2.2.jar'
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
# Lets get the epService provider
|
11
|
+
ep_service = com.espertech.esper.client.EPServiceProviderManager.getDefaultProvider
|
12
|
+
|
13
|
+
# And the configuration
|
14
|
+
ep_config = ep_service.getEPAdministrator.getConfiguration
|
15
|
+
|
16
|
+
class BaseListener
|
17
|
+
include com.espertech.esper.client.UpdateListener
|
18
|
+
def initialize(name)
|
19
|
+
@name = name
|
20
|
+
end
|
21
|
+
def update(newEvents, oldEvents)
|
22
|
+
puts "#{@name} #{Time.now}: " + newEvents.map{|e| e.getUnderlying.inspect}.join(' ')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create an unmatched listener
|
27
|
+
class UnmatchedListener
|
28
|
+
include com.espertech.esper.client.UnmatchedListener
|
29
|
+
|
30
|
+
def update(event)
|
31
|
+
# puts "unmatched:\n- " + event.getProperties.inspect
|
32
|
+
# ignore
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Prepare the OrderEvent type
|
37
|
+
base = {
|
38
|
+
"itemName" => "string",
|
39
|
+
"price" => "double"
|
40
|
+
}
|
41
|
+
ep_config.addEventType('b_test', base)
|
42
|
+
|
43
|
+
ep_config.addEventType('q_test1', base, ['b_test'].to_java(:string))
|
44
|
+
query1 = "SELECT count(*) AS cnt FROM q_test1.win:time_batch(3 seconds) WHERE price > 1.0"
|
45
|
+
ep_service.getEPAdministrator.createEPL(query1).addListener(BaseListener.new('q_test1'))
|
46
|
+
|
47
|
+
ep_config.addEventType('q_test2', base.merge({'amount' => 'int'}), ['b_test'].to_java(:string))
|
48
|
+
query2 = "SELECT count(*) AS cnt FROM q_test2.win:time_batch(3 seconds) WHERE price > 1.0 AND amount > 1"
|
49
|
+
ep_service.getEPAdministrator.createEPL(query2).addListener(BaseListener.new('q_test2'))
|
50
|
+
|
51
|
+
ep_service.getEPRuntime.setUnmatchedListener(UnmatchedListener.new)
|
52
|
+
|
53
|
+
# And finally process the event
|
54
|
+
epr_runtime = ep_service.getEPRuntime
|
55
|
+
|
56
|
+
ep_config.addEventType('e_v1', base, ['q_test1', 'b_test'].to_java(:string))
|
57
|
+
ep_config.addEventType('e_v2', base, ['q_test2', 'q_test1', 'b_test'].to_java(:string))
|
58
|
+
|
59
|
+
t = Time.now + 15
|
60
|
+
while Time.now < t
|
61
|
+
epr_runtime.sendEvent({"itemName"=>"test","price"=>100}, "e_v1")
|
62
|
+
epr_runtime.sendEvent({"itemName"=>"test","amount"=>1,"price"=>300}, "e_v2")
|
63
|
+
epr_runtime.sendEvent({"itemName"=>"test","amount"=>2,"price"=>300}, "e_v2")
|
64
|
+
epr_runtime.sendEvent({"itemName"=>"test","price"=>200}, "e_v1")
|
65
|
+
epr_runtime.sendEvent({"itemName"=>"test","amount"=>3,"price"=>300}, "e_v2")
|
66
|
+
sleep 1
|
67
|
+
end
|
data/lib/norikra.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
unless RUBY_PLATFORM =~ /java/
|
2
|
+
raise LoadError, 'Only supports JRuby'
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'norikra/version'
|
6
|
+
|
7
|
+
require 'norikra/typedef'
|
8
|
+
require 'norikra/query'
|
9
|
+
|
10
|
+
require 'norikra/typedef_manager'
|
11
|
+
require 'norikra/output_pool'
|
12
|
+
require 'norikra/engine'
|
13
|
+
require 'norikra/rpc'
|
data/lib/norikra/cli.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'norikra/server'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Norikra
|
5
|
+
class CLI < Thor
|
6
|
+
desc "start", "start Norikra server process"
|
7
|
+
option :host, :type => :string, :default => '0.0.0.0', :aliases => "-H", :desc => 'host address that server listen [0.0.0.0]'
|
8
|
+
option :port, :type => :numeric, :default => 26571, :aliases => "-P", :desc => 'port that server uses [26571]'
|
9
|
+
# option :config, :type => :string, :default => nil, :aliases => "-c", :desc => 'configuration file to define target/query [none]'
|
10
|
+
# option :daemonize, :type => :boolean, :default => false, :aliases => "-d", :desc => 'daemonize Norikra server [false]'
|
11
|
+
# option :pidfile, :type => :string, :default => '/var/run/norikra.pid', :aliases => "-p", :desc => "pidfile path when daemonized [/var/run/norikra.pid]"
|
12
|
+
# option :logfile, :type => :string, :default => '/var/log/norikra.log', :aliases => "-l", :desc => "logfile path when daemonized [/var/log/norikra.log]"
|
13
|
+
|
14
|
+
#TODO: configuration file to init
|
15
|
+
#TODO: daemonize
|
16
|
+
# TODO: pidcheck
|
17
|
+
# TODO: open logfile & write
|
18
|
+
# TODO: logfile reopen
|
19
|
+
def start
|
20
|
+
server = Norikra::Server.new(options[:host], options[:port])
|
21
|
+
server.run
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'esper-4.9.0.jar'
|
3
|
+
require 'esper/lib/commons-logging-1.1.1.jar'
|
4
|
+
require 'esper/lib/antlr-runtime-3.2.jar'
|
5
|
+
require 'esper/lib/cglib-nodep-2.2.jar'
|
6
|
+
|
7
|
+
require 'norikra/typedef_manager'
|
8
|
+
|
9
|
+
module Norikra
|
10
|
+
class Engine
|
11
|
+
attr_reader :targets, :queries, :output_pool, :typedef_manager
|
12
|
+
|
13
|
+
def initialize(output_pool, typedef_manager=nil)
|
14
|
+
@output_pool = output_pool
|
15
|
+
@typedef_manager = typedef_manager || Norikra::TypedefManager.new()
|
16
|
+
|
17
|
+
@service = com.espertech.esper.client.EPServiceProviderManager.getDefaultProvider
|
18
|
+
@config = @service.getEPAdministrator.getConfiguration
|
19
|
+
|
20
|
+
@mutex = Mutex.new
|
21
|
+
|
22
|
+
# fieldsets already registered into @runtime
|
23
|
+
@registered_fieldsets = {} # {target => {fieldset_summary => Fieldset}
|
24
|
+
|
25
|
+
@targets = []
|
26
|
+
@queries = []
|
27
|
+
|
28
|
+
@waiting_queries = {} # target => [query]
|
29
|
+
end
|
30
|
+
|
31
|
+
def start
|
32
|
+
@runtime = @service.getEPRuntime
|
33
|
+
end
|
34
|
+
|
35
|
+
def stop
|
36
|
+
#TODO: stop to @runtime
|
37
|
+
end
|
38
|
+
|
39
|
+
def open(target, fields=nil)
|
40
|
+
return if @targets.include?(target)
|
41
|
+
open_target(target, fields)
|
42
|
+
end
|
43
|
+
|
44
|
+
def close(target)
|
45
|
+
#TODO: write
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
|
49
|
+
def reserve(target, field, type)
|
50
|
+
@typedef_manager.reserve(target, field, type)
|
51
|
+
end
|
52
|
+
|
53
|
+
def register(query)
|
54
|
+
unless @targets.include?(query.target)
|
55
|
+
open(query.target) # open as lazy defined target
|
56
|
+
end
|
57
|
+
register_query(query)
|
58
|
+
end
|
59
|
+
|
60
|
+
def deregister(query_name)
|
61
|
+
#TODO: write
|
62
|
+
raise NotImplementedError
|
63
|
+
end
|
64
|
+
|
65
|
+
def send(target, events)
|
66
|
+
#TODO: trace log
|
67
|
+
#p events
|
68
|
+
return unless @targets.include?(target) # discard events for target not registered
|
69
|
+
return if events.size < 1
|
70
|
+
|
71
|
+
if @typedef_manager.lazy?(target)
|
72
|
+
base_fieldset = @typedef_manager.generate_base_fieldset(target, events.first)
|
73
|
+
register_base_fieldset(target, base_fieldset)
|
74
|
+
end
|
75
|
+
|
76
|
+
registered_data_fieldset = @registered_fieldsets[target][:data]
|
77
|
+
|
78
|
+
events.each do |event|
|
79
|
+
fieldset = @typedef_manager.refer(target, event)
|
80
|
+
|
81
|
+
unless registered_data_fieldset[fieldset.summary]
|
82
|
+
# register waiting queries including this fieldset, and this fieldset itself
|
83
|
+
register_fieldset(target, fieldset)
|
84
|
+
end
|
85
|
+
#TODO: trace log
|
86
|
+
#p "sendEvent eventType:#{fieldset.event_type_name}, event:#{event.inspect}"
|
87
|
+
@runtime.sendEvent(@typedef_manager.format(target, event).to_java, fieldset.event_type_name)
|
88
|
+
end
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
|
92
|
+
class Listener
|
93
|
+
include com.espertech.esper.client.UpdateListener
|
94
|
+
|
95
|
+
def initialize(query_name, output_pool)
|
96
|
+
@query_name = query_name
|
97
|
+
@output_pool = output_pool
|
98
|
+
end
|
99
|
+
|
100
|
+
def update(new_events, old_events)
|
101
|
+
#TODO: trace log
|
102
|
+
#p "updated event query:#{@query_name}, event:#{new_events.inspect}"
|
103
|
+
@output_pool.push(@query_name, new_events)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
##### Unmatched events are simply ignored
|
107
|
+
# class UnmatchedListener
|
108
|
+
# include com.espertech.esper.client.UnmatchedListener
|
109
|
+
# def update(event)
|
110
|
+
# # puts "unmatched:\n- " + event.getProperties.inspect
|
111
|
+
# # ignore
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def open_target(target, fields)
|
118
|
+
# from open
|
119
|
+
@mutex.synchronize do
|
120
|
+
return if @targets.include?(target)
|
121
|
+
@typedef_manager.add_target(target, fields)
|
122
|
+
@registered_fieldsets[target] = {:base => {}, :query => {}, :data => {}}
|
123
|
+
|
124
|
+
unless @typedef_manager.lazy?(target)
|
125
|
+
base_fieldset = @typedef_manager.base_fieldset(target)
|
126
|
+
|
127
|
+
@typedef_manager.bind_fieldset(target, :base, base_fieldset)
|
128
|
+
register_fieldset_actually(target, base_fieldset, :base)
|
129
|
+
end
|
130
|
+
|
131
|
+
@targets.push(target)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def register_base_fieldset(target, fieldset)
|
136
|
+
# for lazy target, with generated fieldset from sent events.first
|
137
|
+
@mutex.synchronize do
|
138
|
+
return unless @typedef_manager.lazy?(target)
|
139
|
+
|
140
|
+
@typedef_manager.bind_fieldset(target, :base, fieldset)
|
141
|
+
register_fieldset_actually(target, fieldset, :base)
|
142
|
+
|
143
|
+
@typedef_manager.activate(target, fieldset)
|
144
|
+
end
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
def register_query(query)
|
149
|
+
target = query.target
|
150
|
+
@mutex.synchronize do
|
151
|
+
if @typedef_manager.lazy?(target) || @typedef_manager.fields_defined?(target, query.fields)
|
152
|
+
@waiting_queries[target] ||= []
|
153
|
+
@waiting_queries[target].push(query)
|
154
|
+
else
|
155
|
+
query_fieldset = @typedef_manager.generate_query_fieldset(target, query.fields)
|
156
|
+
@typedef_manager.bind_fieldset(target, :query, query_fieldset)
|
157
|
+
register_fieldset_actually(target, query_fieldset, :query)
|
158
|
+
register_query_actually(target, query_fieldset.event_type_name, query)
|
159
|
+
end
|
160
|
+
@queries.push(query)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def register_waiting_queries(target)
|
165
|
+
waitings = @waiting_queries.delete(target) || []
|
166
|
+
not_registered = []
|
167
|
+
|
168
|
+
waitings.each do |query|
|
169
|
+
if @typedef_manager.fields_defined?(target, query.fields)
|
170
|
+
query_fieldset = @typedef_manager.generate_query_fieldset(target, query.fields)
|
171
|
+
@typedef_manager.bind_fieldset(target, :query, query_fieldset)
|
172
|
+
register_fieldset_actually(target, query_fieldset, :query)
|
173
|
+
register_query_actually(target, query_fieldset.event_type_name, query)
|
174
|
+
else
|
175
|
+
not_registered.push(query)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
@waiting_queries[target] = not_registered if not_registered.size > 0
|
180
|
+
end
|
181
|
+
|
182
|
+
def register_fieldset(target, fieldset)
|
183
|
+
@mutex.synchronize do
|
184
|
+
@typedef_manager.bind_fieldset(target, :data, fieldset)
|
185
|
+
|
186
|
+
if @waiting_queries[target]
|
187
|
+
register_waiting_queries(target)
|
188
|
+
end
|
189
|
+
|
190
|
+
register_fieldset_actually(target, fieldset, :data)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# this method should be protected with @mutex lock
|
195
|
+
def register_query_actually(target, stream_name, query)
|
196
|
+
query = query.dup_with_stream_name(stream_name)
|
197
|
+
epl = @service.getEPAdministrator.createEPL(query.expression)
|
198
|
+
epl.java_send :addListener, [com.espertech.esper.client.UpdateListener.java_class], Listener.new(query.name, @output_pool)
|
199
|
+
#TODO: debug log
|
200
|
+
#p "addListener target:#{target}, query_name:#{query.name}, query:#{query.expression}"
|
201
|
+
end
|
202
|
+
|
203
|
+
# this method should be protected with @mutex lock
|
204
|
+
def register_fieldset_actually(target, fieldset, level)
|
205
|
+
return if @registered_fieldsets[target][level][fieldset.summary]
|
206
|
+
|
207
|
+
# Map Supertype (target) and Subtype (typedef name, like TARGET_TypeDefName)
|
208
|
+
# http://esper.codehaus.org/esper-4.9.0/doc/reference/en-US/html/event_representation.html#eventrep-map-supertype
|
209
|
+
# epService.getEPAdministrator().getConfiguration()
|
210
|
+
# .addEventType("AccountUpdate", accountUpdateDef, new String[] {"BaseUpdate"});
|
211
|
+
case level
|
212
|
+
when :base
|
213
|
+
@config.addEventType(fieldset.event_type_name, fieldset.definition)
|
214
|
+
#TODO: debug log
|
215
|
+
#p "addEventType target:#{target}, level:base, eventType:#{fieldset.event_type_name}"
|
216
|
+
when :query
|
217
|
+
base_name = @typedef_manager.base_fieldset(target).event_type_name
|
218
|
+
@config.addEventType(fieldset.event_type_name, fieldset.definition, [base_name].to_java(:string))
|
219
|
+
#TODO: debug log
|
220
|
+
#p "addEventType target:#{target}, level:query, eventType:#{fieldset.event_type_name}, base:#{base_name}"
|
221
|
+
else
|
222
|
+
subset_names = @typedef_manager.subsets(target, fieldset).map(&:event_type_name)
|
223
|
+
@config.addEventType(fieldset.event_type_name, fieldset.definition, subset_names.to_java(:string))
|
224
|
+
#TODO: debug log
|
225
|
+
#p "addEventType target:#{target}, level:data, eventType:#{fieldset.event_type_name}, inherit:#{subset_names.join(',')}"
|
226
|
+
end
|
227
|
+
@registered_fieldsets[target][level][fieldset.summary] = fieldset
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Norikra
|
2
|
+
class OutputPool
|
3
|
+
attr_accessor :pool
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@pool = {}
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def queries
|
11
|
+
@pool.keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(query_name, events)
|
15
|
+
t = Time.now.to_i
|
16
|
+
events = events.map{|e| [t, (e.respond_to?(:getUnderlying) ? e.getUnderlying : e).to_hash]}
|
17
|
+
@mutex.synchronize do
|
18
|
+
@pool[query_name] ||= []
|
19
|
+
@pool[query_name].push(events) if events.size > 0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# returns [[time(int from epoch), event], ...], event: hash
|
24
|
+
def pop(query_name)
|
25
|
+
events = @mutex.synchronize do
|
26
|
+
@pool.delete(query_name) || []
|
27
|
+
end
|
28
|
+
events.reduce(&:+) || []
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns {query_name => [[time, event], ...]}
|
32
|
+
def sweep
|
33
|
+
ret = {}
|
34
|
+
sweep_pool = @mutex.synchronize do
|
35
|
+
sweeped = @pool
|
36
|
+
@pool = {}
|
37
|
+
sweeped
|
38
|
+
end
|
39
|
+
sweep_pool.keys.each do |k|
|
40
|
+
ret[k] = sweep_pool[k].reduce(&:+) || []
|
41
|
+
end
|
42
|
+
ret
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'esper-4.9.0.jar'
|
3
|
+
require 'esper/lib/commons-logging-1.1.1.jar'
|
4
|
+
require 'esper/lib/antlr-runtime-3.2.jar'
|
5
|
+
require 'esper/lib/cglib-nodep-2.2.jar'
|
6
|
+
|
7
|
+
module Norikra
|
8
|
+
class Query
|
9
|
+
attr_accessor :name, :expression
|
10
|
+
|
11
|
+
def initialize(param={})
|
12
|
+
@name = param[:name]
|
13
|
+
@expression = param[:expression]
|
14
|
+
@ast = nil
|
15
|
+
@target = nil
|
16
|
+
@fields = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def dup
|
20
|
+
self.class.new(:name => @name, :expression => @expression.dup)
|
21
|
+
end
|
22
|
+
|
23
|
+
def dup_with_stream_name(actual_name)
|
24
|
+
target = self.target
|
25
|
+
query = self.dup
|
26
|
+
query.expression = self.expression.gsub(/(\s[Ff][Rr][Oo][Mm]\s+)#{target}(\.|\s)/, '\1' + actual_name + '\2')
|
27
|
+
if query.target != actual_name
|
28
|
+
raise RuntimeError, 'failed to replace query target into stream name:' + self.expression
|
29
|
+
end
|
30
|
+
query
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_hash
|
34
|
+
{'name' => @name, 'expression' => @expression, 'target' => self.target}
|
35
|
+
end
|
36
|
+
|
37
|
+
def target
|
38
|
+
return @target if @target
|
39
|
+
#TODO: this code doesn't care JOINs.
|
40
|
+
@target = self.ast.find('STREAM_EXPR').find('EVENT_FILTER_EXPR').children.first.name
|
41
|
+
@target
|
42
|
+
end
|
43
|
+
|
44
|
+
def fields
|
45
|
+
return @fields if @fields
|
46
|
+
#TODO: this code doesn't care JOINs.
|
47
|
+
|
48
|
+
# Norikra::Query.new(
|
49
|
+
# :name => 'hoge',
|
50
|
+
# :expression => 'select count(*) AS cnt from www.win:time_batch(10 seconds) where path="/" AND search.length() > 0').ast.to_a
|
51
|
+
# ["EPL_EXPR",
|
52
|
+
# ["SELECTION_EXPR", ["SELECTION_ELEMENT_EXPR", ["count"], ["cnt"]]],
|
53
|
+
# ["STREAM_EXPR",
|
54
|
+
# ["EVENT_FILTER_EXPR", ["www"]],
|
55
|
+
# ["VIEW_EXPR",
|
56
|
+
# ["win"],
|
57
|
+
# ["time_batch"],
|
58
|
+
# ["TIME_PERIOD", ["SECOND_PART", ["10"]]]]],
|
59
|
+
# ["WHERE_EXPR",
|
60
|
+
# ["EVAL_AND_EXPR",
|
61
|
+
# ["EVAL_EQUALS_EXPR",
|
62
|
+
# ["EVENT_PROP_EXPR", ["EVENT_PROP_SIMPLE", ["path"]]],
|
63
|
+
# ["\"/\""]],
|
64
|
+
# [">",
|
65
|
+
# ["LIB_FUNC_CHAIN", ["LIB_FUNCTION", ["search"], ["length"], ["("]]],
|
66
|
+
# ["0"]]]]]
|
67
|
+
|
68
|
+
ast = self.ast
|
69
|
+
names_simple = ast.listup('EVENT_PROP_SIMPLE').map{|p| p.child.name}
|
70
|
+
names_chain_root = ast.listup('LIB_FUNC_CHAIN').map{|c| c.child.child.name}.select{|n| not self.class.imported_java_class?(n)}
|
71
|
+
@fields = (names_simple + names_chain_root).uniq.sort
|
72
|
+
@fields
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.imported_java_class?(name)
|
76
|
+
return false unless name =~ /^[A-Z]/
|
77
|
+
# Esper auto-imports the following Java library packages:
|
78
|
+
# java.lang.* -> Java::JavaLang::*
|
79
|
+
# java.math.* -> Java::JavaMath::*
|
80
|
+
# java.text.* -> Java::JavaText::*
|
81
|
+
# java.util.* -> Java::JavaUtil::*
|
82
|
+
java_class('Java::JavaLang::'+name) || java_class('Java::JavaMath::'+name) ||
|
83
|
+
java_class('Java::JavaText::'+name) || java_class('Java::JavaUtil::'+name) || false
|
84
|
+
end
|
85
|
+
def self.java_class(const_name)
|
86
|
+
begin
|
87
|
+
c = eval(const_name)
|
88
|
+
c.class == Kernel ? nil : c
|
89
|
+
rescue NameError
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class ParseRuleSelectorImpl
|
95
|
+
include com.espertech.esper.epl.parse.ParseRuleSelector
|
96
|
+
def invokeParseRule(parser)
|
97
|
+
parser.startEPLExpressionRule().getTree()
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class ASTNode
|
102
|
+
attr_accessor :name, :children
|
103
|
+
def initialize(name, children)
|
104
|
+
@name = name
|
105
|
+
@children = children
|
106
|
+
end
|
107
|
+
def to_a
|
108
|
+
[@name] + @children.map(&:to_a)
|
109
|
+
end
|
110
|
+
def child
|
111
|
+
@children.first
|
112
|
+
end
|
113
|
+
def find(node_name) # only one, depth-first search
|
114
|
+
return self if @name == node_name
|
115
|
+
@children.each do |c|
|
116
|
+
r = c.find(node_name)
|
117
|
+
return r if r
|
118
|
+
end
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
def listup(node_name)
|
122
|
+
result = []
|
123
|
+
result.push(self) if @name == node_name
|
124
|
+
@children.each do |c|
|
125
|
+
result.push(*c.listup(node_name))
|
126
|
+
end
|
127
|
+
result
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def ast
|
132
|
+
#TODO: test
|
133
|
+
#TODO: take care for parse error
|
134
|
+
return @ast if @ast
|
135
|
+
rule = ParseRuleSelectorImpl.new
|
136
|
+
target = @expression.dup
|
137
|
+
forerrmsg = @expression.dup
|
138
|
+
result = com.espertech.esper.epl.parse.ParseHelper.parse(target, forerrmsg, true, rule, false)
|
139
|
+
|
140
|
+
def convSubTree(tree)
|
141
|
+
ASTNode.new(tree.text, (tree.children ? tree.children.map{|c| convSubTree(c)} : []))
|
142
|
+
end
|
143
|
+
@ast = convSubTree(result.getTree)
|
144
|
+
@ast
|
145
|
+
end
|
146
|
+
|
147
|
+
### select max(price) as maxprice from HogeTable.win:time_batch(10 sec) where cast(amount, double) > 2 and price > 50
|
148
|
+
# query.ast.to_a
|
149
|
+
# ["EPL_EXPR",
|
150
|
+
# ["SELECTION_EXPR",
|
151
|
+
# ["SELECTION_ELEMENT_EXPR",
|
152
|
+
# ["LIB_FUNC_CHAIN",
|
153
|
+
# ["LIB_FUNCTION",
|
154
|
+
# ["max"],
|
155
|
+
# ["EVENT_PROP_EXPR", ["EVENT_PROP_SIMPLE", ["price"]]],
|
156
|
+
# ["("]]],
|
157
|
+
# ["maxprice"]]],
|
158
|
+
# ["STREAM_EXPR",
|
159
|
+
# ["EVENT_FILTER_EXPR", ["HogeTable"]],
|
160
|
+
# ["VIEW_EXPR",
|
161
|
+
# ["win"],
|
162
|
+
# ["time_batch"],
|
163
|
+
# ["TIME_PERIOD", ["SECOND_PART", ["10"]]]]],
|
164
|
+
# ["WHERE_EXPR",
|
165
|
+
# ["EVAL_AND_EXPR",
|
166
|
+
# [">",
|
167
|
+
# ["cast",
|
168
|
+
# ["EVENT_PROP_EXPR", ["EVENT_PROP_SIMPLE", ["amount"]]],
|
169
|
+
# ["double"]],
|
170
|
+
# ["2"]],
|
171
|
+
# [">", ["EVENT_PROP_EXPR", ["EVENT_PROP_SIMPLE", ["price"]]], ["50"]]]]]
|
172
|
+
end
|
173
|
+
end
|