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.
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