norikra 0.0.13-java → 0.0.14-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/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
|