norikra 0.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/.gitignore +17 -0
  2. data/.ruby-version +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +339 -0
  5. data/README.md +104 -0
  6. data/Rakefile +10 -0
  7. data/bin/norikra +8 -0
  8. data/esper/changelog.txt +1066 -0
  9. data/esper/esper-4.9.0.jar +0 -0
  10. data/esper/esper-license.txt +95 -0
  11. data/esper/esper/lib/antlr-runtime-3.2.jar +0 -0
  12. data/esper/esper/lib/cglib-nodep-2.2.jar +0 -0
  13. data/esper/esper/lib/commons-logging-1.1.1.jar +0 -0
  14. data/esper/esper/lib/esper_3rdparties.license +299 -0
  15. data/esper/esper/lib/log4j-1.2.16.jar +0 -0
  16. data/esper/esper/lib/readme.txt +38 -0
  17. data/esper/esperio-amqp-4.9.0.jar +0 -0
  18. data/esper/esperio-amqp/lib/commons-cli-1.1.jar +0 -0
  19. data/esper/esperio-amqp/lib/commons-io-1.2.jar +0 -0
  20. data/esper/esperio-amqp/lib/esperio_3rdparties.license +1328 -0
  21. data/esper/esperio-amqp/lib/esperio_amqp_jars.txt +2 -0
  22. data/esper/esperio-amqp/lib/rabbitmq-client.jar +0 -0
  23. data/esper/esperio-csv-4.9.0.jar +0 -0
  24. data/esper/esperio-csv/lib/esperio_3rdparties.license +1328 -0
  25. data/esper/esperio-db-4.9.0.jar +0 -0
  26. data/esper/esperio-db/lib/esperio_3rdparties.license +1328 -0
  27. data/esper/esperio-http-4.9.0.jar +0 -0
  28. data/esper/esperio-http/lib/esperio_3rdparties.license +1328 -0
  29. data/esper/esperio-http/lib/httpclient-4.0.1.jar +0 -0
  30. data/esper/esperio-http/lib/httpcore-4.0.1.jar +0 -0
  31. data/esper/esperio-http/lib/httpcore-nio-4.0.1.jar +0 -0
  32. data/esper/esperio-license.txt +95 -0
  33. data/esper/esperio-socket-4.9.0.jar +0 -0
  34. data/esper/esperio-socket/lib/esperio_3rdparties.license +1328 -0
  35. data/esper/esperio-springjms-4.9.0.jar +0 -0
  36. data/esper/esperio-springjms/lib/activation-1.1.jar +0 -0
  37. data/esper/esperio-springjms/lib/activemq-core-5.7.0.jar +0 -0
  38. data/esper/esperio-springjms/lib/activemq-pool-5.7.0.jar +0 -0
  39. data/esper/esperio-springjms/lib/commons-pool-1.6.jar +0 -0
  40. data/esper/esperio-springjms/lib/esperio_3rdparties.license +1328 -0
  41. data/esper/esperio-springjms/lib/geronimo-j2ee-management_1.1_spec-1.0.1.jar +0 -0
  42. data/esper/esperio-springjms/lib/geronimo-jms_1.1_spec-1.1.1.jar +0 -0
  43. data/esper/esperio-springjms/lib/junit-4.8.2.jar +0 -0
  44. data/esper/esperio-springjms/lib/org.springframework.asm-3.1.1.RELEASE.jar +0 -0
  45. data/esper/esperio-springjms/lib/org.springframework.beans-3.1.1.RELEASE.jar +0 -0
  46. data/esper/esperio-springjms/lib/org.springframework.context-3.1.1.RELEASE.jar +0 -0
  47. data/esper/esperio-springjms/lib/org.springframework.core-3.1.1.RELEASE.jar +0 -0
  48. data/esper/esperio-springjms/lib/org.springframework.expression-3.1.1.RELEASE.jar +0 -0
  49. data/esper/esperio-springjms/lib/org.springframework.jms-3.1.1.RELEASE.jar +0 -0
  50. data/esper/esperio-springjms/lib/org.springframework.transaction-3.1.1.RELEASE.jar +0 -0
  51. data/esper/esperio-springjms/lib/slf4j-api-1.7.2.jar +0 -0
  52. data/esper/esperio-springjms/lib/slf4j-log4j12-1.7.2.jar +0 -0
  53. data/esper/esperio-stax-4.9.0.jar +0 -0
  54. data/esper/esperio-stax/lib/axiom-api-1.2.9.jar +0 -0
  55. data/esper/esperio-stax/lib/axiom-c14n-1.2.9.jar +0 -0
  56. data/esper/esperio-stax/lib/axiom-dom-1.2.9.jar +0 -0
  57. data/esper/esperio-stax/lib/axiom-impl-1.2.9.jar +0 -0
  58. data/esper/esperio-stax/lib/commons-logging-1.1.1.jar +0 -0
  59. data/esper/esperio-stax/lib/commons-logging-LICENSE.txt +203 -0
  60. data/esper/esperio-stax/lib/esperio_3rdparties.license +1328 -0
  61. data/esper/esperio-stax/lib/geronimo-activation-LICENSE.txt +203 -0
  62. data/esper/esperio-stax/lib/geronimo-activation_1.1_spec-1.0.2.jar +0 -0
  63. data/esper/esperio-stax/lib/geronimo-javamail-LICENSE.txt +203 -0
  64. data/esper/esperio-stax/lib/geronimo-javamail_1.4_spec-1.6.jar +0 -0
  65. data/esper/esperio-stax/lib/geronimo-stax-api-LICENSE.txt +203 -0
  66. data/esper/esperio-stax/lib/geronimo-stax-api_1.0_spec-1.0.1.jar +0 -0
  67. data/esper/esperio-stax/lib/jaxen-1.1.1.jar +0 -0
  68. data/esper/esperio-stax/lib/jaxen-LICENSE.txt +33 -0
  69. data/esper/esperio-stax/lib/wstx-LICENSE.txt +203 -0
  70. data/esper/esperio-stax/lib/wstx-asl-3.2.9.jar +0 -0
  71. data/junks/esper-test.rb +79 -0
  72. data/junks/glassfish.rb +17 -0
  73. data/junks/mizuno.rb +28 -0
  74. data/junks/simple_test.rb +35 -0
  75. data/junks/type_confliction.rb +46 -0
  76. data/junks/type_conversion.rb +49 -0
  77. data/junks/type_inherit.rb +67 -0
  78. data/lib/norikra.rb +13 -0
  79. data/lib/norikra/cli.rb +24 -0
  80. data/lib/norikra/engine.rb +231 -0
  81. data/lib/norikra/output_pool.rb +45 -0
  82. data/lib/norikra/query.rb +173 -0
  83. data/lib/norikra/rpc.rb +6 -0
  84. data/lib/norikra/rpc/handler.rb +57 -0
  85. data/lib/norikra/rpc/http.rb +36 -0
  86. data/lib/norikra/server.rb +41 -0
  87. data/lib/norikra/typedef.rb +307 -0
  88. data/lib/norikra/typedef_manager.rb +91 -0
  89. data/lib/norikra/version.rb +3 -0
  90. data/norikra.gemspec +33 -0
  91. data/script/spec_server_pry +45 -0
  92. data/spec/field_spec.rb +141 -0
  93. data/spec/fieldset_spec.rb +172 -0
  94. data/spec/output_pool_spec.rb +75 -0
  95. data/spec/query_spec.rb +82 -0
  96. data/spec/spec_helper.rb +55 -0
  97. data/spec/typedef_manager_spec.rb +128 -0
  98. data/spec/typedef_spec.rb +248 -0
  99. 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'
@@ -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