norikra 0.0.1-java
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/.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
|