norikra 0.0.13-java → 0.0.14-java
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/norikra/engine.rb +101 -80
- data/lib/norikra/field.rb +204 -0
- data/lib/norikra/fieldset.rb +167 -0
- data/lib/norikra/logger.rb +37 -22
- data/lib/norikra/query.rb +152 -14
- data/lib/norikra/query/ast.rb +65 -22
- data/lib/norikra/rpc/handler.rb +10 -3
- data/lib/norikra/server.rb +8 -2
- data/lib/norikra/target.rb +24 -0
- data/lib/norikra/typedef.rb +117 -234
- data/lib/norikra/typedef_manager.rb +22 -16
- data/lib/norikra/version.rb +1 -1
- data/norikra.gemspec +1 -1
- data/script/spec_server_pry +31 -0
- data/spec/field_spec.rb +131 -2
- data/spec/fieldset_spec.rb +92 -23
- data/spec/query_spec.rb +204 -29
- data/spec/spec_helper.rb +39 -3
- data/spec/target_spec.rb +18 -0
- data/spec/typedef_manager_spec.rb +35 -12
- data/spec/typedef_spec.rb +235 -24
- metadata +6 -4
data/lib/norikra/engine.rb
CHANGED
@@ -78,34 +78,47 @@ module Norikra
|
|
78
78
|
debug "norikra engine stopped"
|
79
79
|
end
|
80
80
|
|
81
|
-
def open(
|
81
|
+
def open(target_name, fields=nil, auto_field=true)
|
82
82
|
# fields nil || [] => lazy
|
83
83
|
# fields {'fieldname' => 'type'} : type 'string', 'boolean', 'int', 'long', 'float', 'double'
|
84
|
-
info "opening target", :target =>
|
84
|
+
info "opening target", :target => target_name, :fields => fields, :auto_field => auto_field
|
85
|
+
raise Norikra::ArgumentError, "invalid target name" unless Norikra::Target.valid?(target_name)
|
86
|
+
target = Norikra::Target.new(target_name, fields, auto_field)
|
85
87
|
return false if @targets.include?(target)
|
86
|
-
|
87
|
-
open_target(target, fields)
|
88
|
+
open_target(target)
|
88
89
|
end
|
89
90
|
|
90
|
-
def close(
|
91
|
-
info "closing target", :target =>
|
92
|
-
|
93
|
-
|
91
|
+
def close(target_name)
|
92
|
+
info "closing target", :target => target_name
|
93
|
+
targets = @targets.select{|t| t.name == target_name}
|
94
|
+
return false if targets.size != 1
|
95
|
+
target = targets.first
|
96
|
+
@queries.select{|q| q.targets.include?(target.name)}.each do |query|
|
94
97
|
deregister_query(query)
|
95
98
|
end
|
96
99
|
close_target(target)
|
97
100
|
end
|
98
101
|
|
99
|
-
def
|
100
|
-
|
102
|
+
def modify(target_name, auto_field)
|
103
|
+
info "modify target", :target => target_name, :auto_field => auto_field
|
104
|
+
targets = @targets.select{|t| t.name == target_name}
|
105
|
+
if targets.size != 1
|
106
|
+
raise Norikra::ArgumentError, "target name '#{target_name}' not found"
|
107
|
+
end
|
108
|
+
target = targets.first
|
109
|
+
target.auto_field = auto_field
|
110
|
+
end
|
111
|
+
|
112
|
+
def reserve(target_name, field, type)
|
113
|
+
@typedef_manager.reserve(target_name, field, type)
|
101
114
|
end
|
102
115
|
|
103
116
|
def register(query)
|
104
117
|
info "registering query", :name => query.name, :targets => query.targets, :expression => query.expression
|
105
118
|
raise Norikra::ClientError, "query name '#{query.name}' already exists" if @queries.select{|q| q.name == query.name }.size > 0
|
106
119
|
|
107
|
-
query.targets.each do |
|
108
|
-
open(
|
120
|
+
query.targets.each do |target_name|
|
121
|
+
open(target_name) unless @targets.any?{|t| t.name == target_name}
|
109
122
|
end
|
110
123
|
register_query(query)
|
111
124
|
end
|
@@ -118,42 +131,48 @@ module Norikra
|
|
118
131
|
deregister_query(queries.first)
|
119
132
|
end
|
120
133
|
|
121
|
-
def send(
|
122
|
-
trace "send messages", :target =>
|
123
|
-
unless @targets.include?(
|
124
|
-
trace "messages skipped for non-opened target", :target =>
|
134
|
+
def send(target_name, events)
|
135
|
+
trace "send messages", :target => target_name, :events => events
|
136
|
+
unless @targets.include?(target_name) # discard events for target not registered
|
137
|
+
trace "messages skipped for non-opened target", :target => target_name
|
125
138
|
return
|
126
139
|
end
|
127
140
|
return if events.size < 1
|
128
141
|
|
129
|
-
if @typedef_manager.lazy?(
|
130
|
-
info "opening lazy target", :target =>
|
131
|
-
debug "generating base fieldset from event", :target =>
|
132
|
-
base_fieldset = @typedef_manager.generate_base_fieldset(
|
142
|
+
if @typedef_manager.lazy?(target_name)
|
143
|
+
info "opening lazy target", :target => target_name
|
144
|
+
debug "generating base fieldset from event", :target => target_name, :event => events.first
|
145
|
+
base_fieldset = @typedef_manager.generate_base_fieldset(target_name, events.first)
|
133
146
|
|
134
|
-
debug "registering base fieldset", :target =>
|
135
|
-
register_base_fieldset(
|
147
|
+
debug "registering base fieldset", :target => target_name, :base => base_fieldset
|
148
|
+
register_base_fieldset(target_name, base_fieldset)
|
136
149
|
|
137
|
-
info "target successfully opened with fieldset", :target =>
|
150
|
+
info "target successfully opened with fieldset", :target => target_name, :base => base_fieldset
|
138
151
|
end
|
139
152
|
|
140
|
-
registered_data_fieldset = @registered_fieldsets[
|
153
|
+
registered_data_fieldset = @registered_fieldsets[target_name][:data]
|
154
|
+
|
155
|
+
target = @targets.select{|t| t.name == target_name}.first
|
156
|
+
strict_refer = (not target.auto_field?)
|
141
157
|
|
142
158
|
events.each do |event|
|
143
|
-
fieldset = @typedef_manager.refer(
|
159
|
+
fieldset = @typedef_manager.refer(target_name, event, strict_refer)
|
144
160
|
|
145
161
|
unless registered_data_fieldset[fieldset.summary]
|
146
162
|
# register waiting queries including this fieldset, and this fieldset itself
|
147
|
-
debug "registering unknown fieldset", :target =>
|
148
|
-
register_fieldset(
|
163
|
+
debug "registering unknown fieldset", :target => target_name, :fieldset => fieldset
|
164
|
+
register_fieldset(target_name, fieldset)
|
149
165
|
debug "successfully registered"
|
150
166
|
|
151
167
|
# fieldset should be refined, when waiting_queries rewrite inheritance structure and data fieldset be renewed.
|
152
|
-
fieldset = @typedef_manager.refer(
|
168
|
+
fieldset = @typedef_manager.refer(target_name, event, strict_refer)
|
153
169
|
end
|
154
170
|
|
155
|
-
trace "calling sendEvent
|
156
|
-
|
171
|
+
trace "calling sendEvent with bound fieldset (w/ valid event_type_name)", :target => target_name, :event => event
|
172
|
+
trace "This is assert for valid event_type_name", :event_type_name => fieldset.event_type_name
|
173
|
+
formed = fieldset.format(event)
|
174
|
+
trace "sendEvent", :data => formed
|
175
|
+
@runtime.sendEvent(formed.to_java, fieldset.event_type_name)
|
157
176
|
end
|
158
177
|
nil
|
159
178
|
end
|
@@ -202,18 +221,18 @@ module Norikra
|
|
202
221
|
|
203
222
|
private
|
204
223
|
|
205
|
-
def open_target(target
|
224
|
+
def open_target(target)
|
206
225
|
@mutex.synchronize do
|
207
226
|
return false if @targets.include?(target)
|
208
227
|
|
209
|
-
@typedef_manager.add_target(target, fields)
|
210
|
-
@registered_fieldsets[target] = {:base => {}, :query => {}, :data => {}}
|
228
|
+
@typedef_manager.add_target(target.name, target.fields)
|
229
|
+
@registered_fieldsets[target.name] = {:base => {}, :query => {}, :data => {}}
|
211
230
|
|
212
|
-
unless @typedef_manager.lazy?(target)
|
213
|
-
base_fieldset = @typedef_manager.base_fieldset(target)
|
231
|
+
unless @typedef_manager.lazy?(target.name)
|
232
|
+
base_fieldset = @typedef_manager.base_fieldset(target.name)
|
214
233
|
|
215
|
-
@typedef_manager.bind_fieldset(target, :base, base_fieldset)
|
216
|
-
register_fieldset_actually(target, base_fieldset, :base)
|
234
|
+
@typedef_manager.bind_fieldset(target.name, :base, base_fieldset)
|
235
|
+
register_fieldset_actually(target.name, base_fieldset, :base)
|
217
236
|
end
|
218
237
|
|
219
238
|
@targets.push(target)
|
@@ -225,33 +244,33 @@ module Norikra
|
|
225
244
|
@mutex.synchronize do
|
226
245
|
return false unless @targets.include?(target)
|
227
246
|
|
228
|
-
@typedef_manager.remove_target(target)
|
229
|
-
@registered_fieldsets.delete(target)
|
247
|
+
@typedef_manager.remove_target(target.name)
|
248
|
+
@registered_fieldsets.delete(target.name)
|
230
249
|
|
231
250
|
@targets.delete(target)
|
232
251
|
end
|
233
252
|
true
|
234
253
|
end
|
235
254
|
|
236
|
-
def register_base_fieldset(
|
255
|
+
def register_base_fieldset(target_name, fieldset)
|
237
256
|
# for lazy target, with generated fieldset from sent events.first
|
238
257
|
@mutex.synchronize do
|
239
|
-
return false unless @typedef_manager.lazy?(
|
258
|
+
return false unless @typedef_manager.lazy?(target_name)
|
240
259
|
|
241
|
-
@typedef_manager.activate(
|
242
|
-
register_fieldset_actually(
|
260
|
+
@typedef_manager.activate(target_name, fieldset)
|
261
|
+
register_fieldset_actually(target_name, fieldset, :base)
|
243
262
|
end
|
244
263
|
true
|
245
264
|
end
|
246
265
|
|
247
|
-
def update_inherits_graph(
|
266
|
+
def update_inherits_graph(target_name, query_fieldset)
|
248
267
|
# replace registered data fieldsets with new fieldset inherits this query fieldset
|
249
|
-
@typedef_manager.supersets(
|
268
|
+
@typedef_manager.supersets(target_name, query_fieldset).each do |set|
|
250
269
|
rebound = set.rebind(true) # update event_type_name with new inheritations
|
251
270
|
|
252
|
-
register_fieldset_actually(
|
253
|
-
@typedef_manager.replace_fieldset(
|
254
|
-
deregister_fieldset_actually(
|
271
|
+
register_fieldset_actually(target_name, rebound, :data, true) # replacing on esper engine
|
272
|
+
@typedef_manager.replace_fieldset(target_name, set, rebound)
|
273
|
+
deregister_fieldset_actually(target_name, set.event_type_name, :data)
|
255
274
|
end
|
256
275
|
end
|
257
276
|
|
@@ -261,16 +280,18 @@ module Norikra
|
|
261
280
|
|
262
281
|
unless @typedef_manager.ready?(query)
|
263
282
|
@waiting_queries.push(query)
|
283
|
+
trace "waiting query fields", :targets => query.targets, :fields => query.targets.map{|t| query.fields(t)}
|
284
|
+
@typedef_manager.register_waiting_fields(query)
|
264
285
|
@queries.push(query)
|
265
286
|
return
|
266
287
|
end
|
267
288
|
|
268
289
|
mapping = @typedef_manager.generate_fieldset_mapping(query)
|
269
|
-
mapping.each do |
|
270
|
-
@typedef_manager.bind_fieldset(
|
271
|
-
register_fieldset_actually(
|
272
|
-
update_inherits_graph(
|
273
|
-
query.fieldsets[
|
290
|
+
mapping.each do |target_name, query_fieldset|
|
291
|
+
@typedef_manager.bind_fieldset(target_name, :query, query_fieldset)
|
292
|
+
register_fieldset_actually(target_name, query_fieldset, :query)
|
293
|
+
update_inherits_graph(target_name, query_fieldset)
|
294
|
+
query.fieldsets[target_name] = query_fieldset
|
274
295
|
end
|
275
296
|
|
276
297
|
register_query_actually(query, mapping)
|
@@ -289,19 +310,19 @@ module Norikra
|
|
289
310
|
if @waiting_queries.include?(query)
|
290
311
|
@waiting_queries.delete(query)
|
291
312
|
else
|
292
|
-
query.fieldsets.each do |
|
313
|
+
query.fieldsets.each do |target_name, query_fieldset|
|
293
314
|
removed_event_type_name = query_fieldset.event_type_name
|
294
315
|
|
295
|
-
@typedef_manager.unbind_fieldset(
|
296
|
-
update_inherits_graph(
|
297
|
-
deregister_fieldset_actually(
|
316
|
+
@typedef_manager.unbind_fieldset(target_name, :query, query_fieldset)
|
317
|
+
update_inherits_graph(target_name, query_fieldset)
|
318
|
+
deregister_fieldset_actually(target_name, removed_event_type_name, :query)
|
298
319
|
end
|
299
320
|
end
|
300
321
|
end
|
301
322
|
true
|
302
323
|
end
|
303
324
|
|
304
|
-
def register_waiting_queries
|
325
|
+
def register_waiting_queries
|
305
326
|
ready = []
|
306
327
|
not_ready = []
|
307
328
|
@waiting_queries.each do |q|
|
@@ -315,25 +336,25 @@ module Norikra
|
|
315
336
|
|
316
337
|
ready.each do |query|
|
317
338
|
mapping = @typedef_manager.generate_fieldset_mapping(query)
|
318
|
-
mapping.each do |
|
319
|
-
@typedef_manager.bind_fieldset(
|
320
|
-
register_fieldset_actually(
|
321
|
-
update_inherits_graph(
|
322
|
-
query.fieldsets[
|
339
|
+
mapping.each do |target_name, query_fieldset|
|
340
|
+
@typedef_manager.bind_fieldset(target_name, :query, query_fieldset)
|
341
|
+
register_fieldset_actually(target_name, query_fieldset, :query)
|
342
|
+
update_inherits_graph(target_name, query_fieldset)
|
343
|
+
query.fieldsets[target_name] = query_fieldset
|
323
344
|
end
|
324
345
|
register_query_actually(query, mapping)
|
325
346
|
end
|
326
347
|
end
|
327
348
|
|
328
|
-
def register_fieldset(
|
349
|
+
def register_fieldset(target_name, fieldset)
|
329
350
|
@mutex.synchronize do
|
330
|
-
@typedef_manager.bind_fieldset(
|
351
|
+
@typedef_manager.bind_fieldset(target_name, :data, fieldset)
|
331
352
|
|
332
353
|
if @waiting_queries.size > 0
|
333
|
-
register_waiting_queries
|
354
|
+
register_waiting_queries
|
334
355
|
end
|
335
|
-
|
336
|
-
register_fieldset_actually(
|
356
|
+
debug "registering data fieldset", :target => target_name, :fields => fieldset.fields
|
357
|
+
register_fieldset_actually(target_name, fieldset, :data)
|
337
358
|
end
|
338
359
|
end
|
339
360
|
|
@@ -359,7 +380,7 @@ module Norikra
|
|
359
380
|
administrator = @service.getEPAdministrator
|
360
381
|
|
361
382
|
statement_model = administrator.compileEPL(query.expression)
|
362
|
-
Norikra::Query.
|
383
|
+
Norikra::Query.rewrite_query(statement_model, event_type_name_map)
|
363
384
|
|
364
385
|
epl = administrator.create(statement_model)
|
365
386
|
epl.java_send :addListener, [com.espertech.esper.client.UpdateListener.java_class], Listener.new(query.name, query.group, @output_pool)
|
@@ -379,8 +400,8 @@ module Norikra
|
|
379
400
|
end
|
380
401
|
|
381
402
|
# this method should be protected with @mutex lock
|
382
|
-
def register_fieldset_actually(
|
383
|
-
return if level == :data && @registered_fieldsets[
|
403
|
+
def register_fieldset_actually(target_name, fieldset, level, replace=false)
|
404
|
+
return if level == :data && @registered_fieldsets[target_name][level][fieldset.summary] && !replace
|
384
405
|
|
385
406
|
# Map Supertype (target) and Subtype (typedef name, like TARGET_TypeDefName)
|
386
407
|
# http://esper.codehaus.org/esper-4.9.0/doc/reference/en-US/html/event_representation.html#eventrep-map-supertype
|
@@ -388,29 +409,29 @@ module Norikra
|
|
388
409
|
# .addEventType("AccountUpdate", accountUpdateDef, new String[] {"BaseUpdate"});
|
389
410
|
case level
|
390
411
|
when :base
|
391
|
-
debug "add event type", :target =>
|
412
|
+
debug "add event type", :target => target_name, :level => 'base', :event_type => fieldset.event_type_name
|
392
413
|
@config.addEventType(fieldset.event_type_name, fieldset.definition)
|
393
414
|
when :query
|
394
|
-
base_name = @typedef_manager.base_fieldset(
|
395
|
-
debug "add event type", :target =>
|
415
|
+
base_name = @typedef_manager.base_fieldset(target_name).event_type_name
|
416
|
+
debug "add event type", :target => target_name, :level => 'query', :event_type => fieldset.event_type_name, :base => base_name
|
396
417
|
@config.addEventType(fieldset.event_type_name, fieldset.definition, [base_name].to_java(:string))
|
397
418
|
else
|
398
|
-
subset_names = @typedef_manager.subsets(
|
399
|
-
debug "add event type", :target =>
|
419
|
+
subset_names = @typedef_manager.subsets(target_name, fieldset).map(&:event_type_name)
|
420
|
+
debug "add event type", :target => target_name, :level => 'data', :event_type => fieldset.event_type_name, :inherit => subset_names
|
400
421
|
@config.addEventType(fieldset.event_type_name, fieldset.definition, subset_names.to_java(:string))
|
401
422
|
|
402
|
-
@registered_fieldsets[
|
423
|
+
@registered_fieldsets[target_name][level][fieldset.summary] = fieldset
|
403
424
|
end
|
404
425
|
nil
|
405
426
|
end
|
406
427
|
|
407
428
|
# this method should be protected with @mutex lock as same as register
|
408
|
-
def deregister_fieldset_actually(
|
429
|
+
def deregister_fieldset_actually(target_name, event_type_name, level)
|
409
430
|
return if level == :base
|
410
431
|
|
411
|
-
# DON'T check @registered_fieldsets[
|
432
|
+
# DON'T check @registered_fieldsets[target_name][level][fieldset.summary]
|
412
433
|
# removed fieldset should be already replaced with register_fieldset_actually w/ replace flag
|
413
|
-
debug "remove event type", :target =>
|
434
|
+
debug "remove event type", :target => target_name, :event_type => event_type_name
|
414
435
|
@config.removeEventType(event_type_name, true)
|
415
436
|
end
|
416
437
|
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'norikra/error'
|
2
|
+
|
3
|
+
module Norikra
|
4
|
+
class Field
|
5
|
+
### esper types
|
6
|
+
### http://esper.codehaus.org/esper-4.9.0/doc/reference/en-US/html/epl_clauses.html#epl-syntax-datatype
|
7
|
+
# string A single character to an unlimited number of characters.
|
8
|
+
# boolean A boolean value.
|
9
|
+
# integer An integer value (4 byte).
|
10
|
+
# long A long value (8 byte). Use the "L" or "l" (lowercase L) suffix. # select 1L as field1, 1l as field2
|
11
|
+
# double A double-precision 64-bit IEEE 754 floating point. # select 1.67 as field1, 167e-2 as field2, 1.67d as field3
|
12
|
+
# float A single-precision 32-bit IEEE 754 floating point. Use the "f" suffix. # select 1.2f as field1, 1.2F as field2
|
13
|
+
# byte A 8-bit signed two's complement integer. # select 0x10 as field1
|
14
|
+
#
|
15
|
+
### norikra types of container
|
16
|
+
# hash A single value which is represented as Hash class (ex: parsed json object), and can be nested with hash/array
|
17
|
+
# # select h.value1, h.value2.value3 #<= "h":{"value1":"...","value2":{"value3":"..."}}
|
18
|
+
# Hash key item as "String of Numbers" be escaped with '$$'.
|
19
|
+
# # select h.$$3 #<= "h":{"3":3}
|
20
|
+
#
|
21
|
+
# array A single value which is represented as Array class (ex: parsed json array), and can be nested with hash/array
|
22
|
+
# # select h.$0, h.$1.$0.name #<= "h":["....", [{"name":"value..."}]]
|
23
|
+
#
|
24
|
+
#### 'integer' in epser document IS WRONG.
|
25
|
+
#### If 'integer' specified, esper raises this exception:
|
26
|
+
### Exception: Nestable type configuration encountered an unexpected property type name 'integer' for property 'status',
|
27
|
+
### expected java.lang.Class or java.util.Map or the name of a previously-declared Map or ObjectArray type
|
28
|
+
#### Correct type name is 'int'. see and run 'junks/esper-test.rb'
|
29
|
+
|
30
|
+
attr_accessor :name, :type, :optional, :escaped_name, :container_name, :container_type
|
31
|
+
|
32
|
+
def initialize(name, type, optional=nil)
|
33
|
+
@name = name.to_s
|
34
|
+
@type = self.class.valid_type?(type)
|
35
|
+
@optional = optional
|
36
|
+
|
37
|
+
@escaped_name = self.class.escape_name(@name)
|
38
|
+
|
39
|
+
@container_name = @container_type = nil
|
40
|
+
|
41
|
+
@chained_access = !!@name.index('.')
|
42
|
+
if @chained_access
|
43
|
+
parts = @name.split(/(?<!\.)\./)
|
44
|
+
@container_name = parts[0]
|
45
|
+
@container_type = parts[1] =~ /^(\$)?\d+$/ ? 'array' : 'hash'
|
46
|
+
@optional = true
|
47
|
+
end
|
48
|
+
|
49
|
+
define_value_accessor(@name, @chained_access)
|
50
|
+
end
|
51
|
+
|
52
|
+
def container_field?
|
53
|
+
@type == 'hash' || @type == 'array'
|
54
|
+
end
|
55
|
+
|
56
|
+
def chained_access?
|
57
|
+
@chained_access
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.escape_name(name)
|
61
|
+
# hoge.pos #=> "hoge$pos"
|
62
|
+
# hoge.0 #=> "hoge$$0"
|
63
|
+
# hoge.$0 #=> "hoge$$0"
|
64
|
+
# hoge.$$0 #=> "hoge$$$0"
|
65
|
+
|
66
|
+
# hoge..pos #=> "hoge$_pos"
|
67
|
+
# hoge...pos #=> "hoge$__pos"
|
68
|
+
|
69
|
+
parts = name.split(/(?<!\.)\./).map do |part|
|
70
|
+
if part =~ /^\d+$/
|
71
|
+
'$' + part.to_s
|
72
|
+
else
|
73
|
+
part.gsub(/[^$_a-zA-Z0-9]/,'_')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
parts.join('$')
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.regulate_key_chain(keys)
|
80
|
+
keys.map{|key|
|
81
|
+
case
|
82
|
+
when key.is_a?(Integer) then '$' + key.to_s
|
83
|
+
when key.is_a?(String) && key =~ /^[0-9]+$/ then '$$' + key.to_s
|
84
|
+
else key.to_s.gsub(/[^$_a-zA-Z0-9]/,'_')
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.escape_key_chain(*keys)
|
90
|
+
# "hoge", "pos" #=> "hoge$pos"
|
91
|
+
# "hoge", 3 #=> "hoge$$3"
|
92
|
+
# "hoge", "3" #=> "hoge$$$3"
|
93
|
+
# "hoge", ".pos" #=> "hoge
|
94
|
+
regulate_key_chain(keys).join('$')
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_hash(sym=false)
|
98
|
+
if sym
|
99
|
+
{name: @name, type: @type, optional: @optional}
|
100
|
+
else
|
101
|
+
{'name' => @name, 'type' => @type, 'optional' => @optional}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def dup(optional=nil)
|
106
|
+
self.class.new(@name, @type, optional.nil? ? @optional : optional)
|
107
|
+
end
|
108
|
+
|
109
|
+
def ==(other)
|
110
|
+
self.name == other.name && self.type == other.type && self.optional == other.optional
|
111
|
+
end
|
112
|
+
|
113
|
+
def optional? # used outside of FieldSet
|
114
|
+
@optional
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.container_type?(type)
|
118
|
+
case type.to_s.downcase
|
119
|
+
when 'hash' then true
|
120
|
+
when 'array' then true
|
121
|
+
else
|
122
|
+
false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.valid_type?(type)
|
127
|
+
case type.to_s.downcase
|
128
|
+
when 'string' then 'string'
|
129
|
+
when 'boolean' then 'boolean'
|
130
|
+
when 'int' then 'int'
|
131
|
+
when 'long' then 'long'
|
132
|
+
when 'float' then 'float'
|
133
|
+
when 'double' then 'double'
|
134
|
+
when 'hash' then 'hash'
|
135
|
+
when 'array' then 'array'
|
136
|
+
else
|
137
|
+
raise Norikra::ArgumentError, "invalid field type '#{type}'"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# def value(event) # by define_value_accessor
|
142
|
+
|
143
|
+
def format(value, element_path=nil) #element_path ex: 'fname.fchild', 'fname.$0', 'f.fchild.$2'
|
144
|
+
case @type
|
145
|
+
when 'string' then value.to_s
|
146
|
+
when 'boolean' then value =~ /^(true|false)$/i ? ($1.downcase == 'true') : (!!value)
|
147
|
+
when 'long','int' then value.to_i
|
148
|
+
when 'double','float' then value.to_f
|
149
|
+
when 'hash', 'array'
|
150
|
+
raise RuntimeError, "container field not permitted to access directly, maybe BUG. name:#{@name},type:#{@type}"
|
151
|
+
else
|
152
|
+
raise RuntimeError, "unknown field type (in format), maybe BUG. name:#{@name},type:#{@type}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def define_value_accessor(name, chained)
|
157
|
+
# "fieldname" -> def value(event) ; event["fieldname"] ; end
|
158
|
+
# "fieldname.key1" -> def value(event) ; event["fieldname"]["key1"] ; end
|
159
|
+
# "fieldname.key1.$$2" -> def value(event) ; event["fieldname"]["key1"]["2"] ; end
|
160
|
+
# "fieldname.2" -> def value(event) ; event["fieldname"][2] ; end
|
161
|
+
# "fieldname.$2" -> def value(event) ; event["fieldname"][2] ; end
|
162
|
+
|
163
|
+
unless chained
|
164
|
+
@accessors = [name]
|
165
|
+
self.instance_eval do
|
166
|
+
def value(event)
|
167
|
+
event[@accessors.first]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
return
|
171
|
+
end
|
172
|
+
|
173
|
+
@accessors = name.split(/(?<!\.)\./).map do |part|
|
174
|
+
case part
|
175
|
+
when /^\d+$/ then part.to_i
|
176
|
+
when /^\$(\d+)$/ then $1.to_i
|
177
|
+
when /^\$\$(\d+)$/ then $1.to_s
|
178
|
+
else part
|
179
|
+
end
|
180
|
+
end
|
181
|
+
self.instance_eval do
|
182
|
+
def safe_fetch(v, accessor)
|
183
|
+
unless accessor.is_a?(String) || accessor.is_a?(Fixnum)
|
184
|
+
raise ArgumentError, "container_accessor must be a String or Interger, but #{accessor.class.to_s}"
|
185
|
+
end
|
186
|
+
if v.is_a?(Hash)
|
187
|
+
v[accessor] || v[accessor.to_s] # hash[string] is valid, and hash[int] is also valid, and hash["int"] is valid too.
|
188
|
+
elsif v.is_a?(Array)
|
189
|
+
if accessor.is_a?(Fixnum)
|
190
|
+
v[accessor]
|
191
|
+
else # String -> Hash expected
|
192
|
+
nil
|
193
|
+
end
|
194
|
+
else # non-container value
|
195
|
+
nil
|
196
|
+
end
|
197
|
+
end
|
198
|
+
def value(event)
|
199
|
+
@accessors.reduce(event){|e,a| safe_fetch(e, a)}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|