Please disable Adblockers and enable JavaScript for domain CEWebS.cs.univie.ac.at! We have NO ADS, but they may interfere with some of our course material.

Name: lib/remar.rb 
1:
# runtime event monitoring, analysis and response
2:
require 'thread'
3:
 
4:
class Symbol# {{{
5:
  def <=>(s)
6:
    self.to_s <=> s.to_s
7:
  end
8:
end# }}}
9:
class Array# {{{
10:
  def subset?(other)
11:
    self.each do |x|
12:
     return false unless other.include?(x)
13:
    end
14:
    true
15:
  end
16:
 
17:
  def superset?(other)
18:
    other.subset?(self)
19:
  end
20:
end# }}}
21:
 
22:
class REMAR
23:
  class RuleBailout < ::RuntimeError; end
24:
  class RuleError < ::RuntimeError; end
25:
  class RulesetError < ::StandardError; end
26:
  class BlockError < ::StandardError; end
27:
 
28:
  class Context# {{{
29:
    def initialize(context,dirty)
30:
      @context = context
31:
      @dirty = dirty
32:
    end
33:
 
34:
    def method_missing(name,*args,&blk)
35:
      return [:context,name,blk] if block_given? && args.empty?
36:
      if !block_given? && args.empty?
37:
        unless @dirty.has_key?(name)
38:
          @dirty[name] = Marshal.load(Marshal.dump(@context[name]))
39:
        end
40:
        return Realization.new(@context[name])
41:
      end
42:
    end
43:
  end# }}}
44:
  class Events# {{{
45:
    def initialize(events)
46:
      @events = events
47:
    end
48:
 
49:
    def method_missing(name,*args,&blk)
50:
      if block_given? && args.empty?
51:
        return [:event,name,blk]
52:
      elsif !block_given? && args.empty?
53:
        return [:event,name,Proc.new{true}]
54:
      end
55:
    end
56:
  end# }}}
57:
 
58:
  class Realization# {{{
59:
    def initialize(values)
60:
      @values = values
61:
    end
62:
    def method_missing(name,*args)
63:
      temp = nil
64:
      if args.empty? && @values.has_key?(name)
65:
        @values[name]
66:
      elsif @values.keys.find{|f| temp = f.to_s; temp == name.to_s[0..(temp.length-1)] }
67:
        op = name.to_s[temp.length..-1]
68:
        case op
69:
          when "="
70:
            @values[temp.to_sym] = args[0]
71:
        end
72:
      else
73:
        super
74:
      end
75:
    end
76:
  end# }}}
77:
  class RuleRealization# {{{
78:
    def initialize(event,context,calls,timers,default)
79:
      @event   = event
80:
      @context = context
81:
      @calls   = calls
82:
      @default = default
83:
      @timers  = timers
84:
    end
85:
    def event
86:
      Realization.new(@event)
87:
    end
88:
    def context
89:
      @context
90:
    end
91:
    def timed(seconds,&what)
92:
      @timers << [seconds,what]
93:
    end
94:
    def method_missing(name,*args)
95:
      if @calls.has_key?(name)
96:
        if @calls[name].nil?
97:
          unless @default.nil?
98:
            @default.call(name,args)
99:
          end
100:
        else
101:
          @calls[name].call(*args)
102:
        end
103:
      end
104:
    end
105:
  end# }}}
106:
  class RulesetRealization# {{{
107:
    def initialize(main,values,events,context,calls,rules_context,rules_event,c_events,c_context)
108:
      @main          = main
109:
      @values        = values
110:
      @events        = events
111:
      @context       = context
112:
      @calls         = calls
113:
      @rules_context = rules_context
114:
      @rules_event   = rules_event
115:
      @c_events      = c_events
116:
      @c_context     = c_context
117:
    end
118:
 
119:
    def value(name, identifier, value=nil)# {{{
120:
      if name.is_a?(Symbol)
121:
        @values[name] ||= {}
122:
        if value.nil?
123:
          @values[name][identifier] = identifier
124:
        elsif value.is_a?(Symbol)
125:
          @values[name][identifier] = value
126:
        end
127:
      end
128:
    end# }}}
129:
    def event(*para)# {{{
130:
      if !para.empty? && para[0].is_a?(Symbol)
131:
        @events[para[0]] ||= []
132:
        para[1..-1].each do |value|
133:
          @events[para[0]] << value if value.is_a?(Symbol)
134:
        end
135:
        @events[para[0]].sort!
136:
      end
137:
      return @c_events if para.empty?
138:
      nil
139:
    end# }}}
140:
    def context(*para)# {{{
141:
      if !para.empty? && para[0].is_a?(Symbol)
142:
        @context[para[0]] ||= {}
143:
        para[1..-1].each do |value|
144:
          if value.is_a?(Hash)
145:
            value.each do |k,v|
146:
              @context[para[0]][k] = v if k.is_a?(Symbol)
147:
            end
148:
          end
149:
        end
150:
      end
151:
      return @c_context if para.empty?
152:
      nil
153:
    end# }}}
154:
    def call(name)# {{{
155:
      if name.is_a?(Symbol) && !@calls.include?(name)
156:
        @calls[name] = nil
157:
        (class << @main; self; end).class_eval do
158:
          define_method "on_#{name}".to_sym do |&blk|
159:
            @calls[name] = blk
160:
          end
161:
        end
162:
      end
163:
    end# }}}
164:
    def rule(*prop,&blk)# {{{
165:
      estate = nil
166:
      prop.each do |p|
167:
        if p[0] == :event && estate.nil?
168:
          estate = prop.delete(p)
169:
        elsif p[0] == :event && !estate.nil?
170:
          raise RuleError, "rule with more than 1 event fount"
171:
        end
172:
      end
173:
      if estate
174:
        @rules_event[estate[1]] ||= []
175:
        @rules_event[estate[1]] << [estate[2],prop,blk]
176:
      else
177:
        prop.each do |p|
178:
          @rules_context[p[1]] ||= []
179:
          @rules_context[p[1]] << [prop,blk]
180:
        end
181:
      end
182:
    end# }}}
183:
  end# }}}
184:
 
185:
   def initialize# {{{
186:
    @before_push = nil
187:
    @after_push = nil
188:
    @default = nil
189:
    @dirty = {}
190:
    @values = {}
191:
    @events = {}
192:
    @context = {}
193:
    @calls = {}
194:
    @rules_event = {}
195:
    @rules_context = {}
196:
    @c_events = Events.new(@events)
197:
    @c_context = Context.new(@context,@dirty)
198:
    @mutex = Mutex.new
199:
    @timers = []
200:
    @rulesetrealization = RulesetRealization.new(self,@values,@events,@context,@calls,@rules_context,@rules_event,@c_events,@c_context)
201:
  end# }}}
202:
 
203:
private
204:
 
205:
  def __dirty_recursive# {{{
206:
    return if @dirty.empty?
207:
    confirmation = []
208:
    @dirty.each do |d,c|
209:
      c.each do |k,v|
210:
        if @context[d][k] != v
211:
          confirmation << d
212:
        end
213:
      end
214:
    end
215:
    @dirty.clear
216:
    confirmation.each do |conf|
217:
      if @rules_context.has_key?(conf)
218:
        @rules_context[conf].each do |e|
219:
          begin
220:
            e[0].each do |c|
221:
              Realization.new(@context[c[1]]).instance_eval(&c[2]) || raise(RuleBailout)
222:
            end
223:
            RuleRealization.new({},@c_context,@calls,@timers,@default).instance_eval(&e[1])
224:
          rescue RuleBailout
225:
          end
226:
        end
227:
      end
228:
    end
229:
    __dirty_recursive
230:
  end  # }}}
231:
  def __cleanup# {{{
232:
    @values.clear
233:
    @events.clear
234:
    @context.clear
235:
    @calls.clear
236:
    @rules_event.clear
237:
    @rules_context.clear
238:
  end# }}}
239:
  def __set_timer(data,seconds,what)# {{{
240:
    Thread.new do
241:
      sleep seconds
242:
      @mutex.synchronize do
243:
        begin
244:
          RuleRealization.new(data,@c_context,@calls,@timers,@default).instance_eval(&what)
245:
        rescue RuleBailout
246:
        end
247:
        __dirty_recursive
248:
        @after_push.call(@context) unless @after_push.nil?
249:
        @timers.delete_if do |seconds,what|
250:
          __set_timer(data,seconds,what)
251:
          true
252:
        end
253:
      end
254:
    end
255:
  end# }}}
256:
 
257:
public
258:
  attr_reader :context
259:
 
260:
    def clear(what=nil)# {{{
261:
      case what
262:
        when nil, :context
263:
          @context.clear
264:
        when nil, :events
265:
          @events.clear
266:
        when nil, :values
267:
          @values.clear
268:
        when nil, :rules
269:
          @rules_event.clear
270:
          @rules_context.clear
271:
        when nil, :calls
272:
          @calls.clear
273:
       end
274:
       true
275:
    end# }}}
276:
 
277:
  def default(&blk)# {{{
278:
    @default = blk if block_given?
279:
  end# }}}
280:
 
281:
  def ruleset(code = nil,&blk)# {{{
282:
    if code.nil? && !block_given?
283:
      @rulesetrealization
284:
    else
285:
      unless block_given?
286:
        blk = Proc.new do
287:
          begin
288:
            eval("#{code}")
289:
          rescue SyntaxError => err
290:
            raise RulesetError, err.message, err.backtrace
291:
          end
292:
        end
293:
      end
294:
      begin
295:
        __cleanup
296:
        @rulesetrealization.instance_eval(&blk)
297:
      rescue => err
298:
        raise RulesetError, err.message, err.backtrace
299:
      end
300:
      self
301:
    end
302:
  end# }}}
303:
 
304:
  def test_push(name,data)# {{{
305:
    evt_data = data.keys.sort
306:
    evt_name = @events.find{|k,v| v.subset?(evt_data) && k == name }
307:
 
308:
    if evt_name.nil?
309:
      false
310:
    else
311:
      evt_name = evt_name[0]
312:
      # map values
313:
      data.each do |d,i|
314:
        if @values.has_key?(d) && @values[d].has_key?(i)
315:
          data[d] = @values[d][i]
316:
        end
317:
      end
318:
 
319:
      # when values are defined, accept only this values
320:
      @events[evt_name].each do |ee|
321:
        unless @values[ee].nil?
322:
          unless @values[ee].values.include?(data[ee])
323:
            return false
324:
          end
325:
        end
326:
      end
327:
 
328:
      true
329:
    end
330:
  end# }}}
331:
 
332:
  def push(name,data)# {{{
333:
    evt_data = data.keys.sort
334:
    evt_name = @events.find{|k,v| v.subset?(evt_data) && k == name }
335:
 
336:
    if evt_name.nil?
337:
      false
338:
    else
339:
      evt_name = evt_name[0]
340:
      # map values
341:
      data.each do |d,i|
342:
        if @values.has_key?(d) && @values[d].has_key?(i)
343:
          data[d] = @values[d][i]
344:
        end
345:
      end
346:
 
347:
      # when values are defined, accept only these values
348:
      @events[evt_name].each do |ee|
349:
        unless @values[ee].nil?
350:
          unless @values[ee].values.include?(data[ee])
351:
            return false
352:
          end
353:
        end
354:
      end
355:
 
356:
      return false if @rules_event[evt_name].nil?
357:
 
358:
      @mutex.synchronize do
359:
        @before_push.call(name,data,@context) unless @before_push.nil?
360:
        @rules_event[evt_name].each do |e|
361:
          begin
362:
            Realization.new(data).instance_eval(&e[0]) || raise(RuleBailout)
363:
            e[1].each do |c|
364:
              Realization.new(@context[c[1]]).instance_eval(&c[2]) || raise(RuleBailout)
365:
            end
366:
            RuleRealization.new(data,@c_context,@calls,@timers,@default).instance_eval(&e[2])
367:
          rescue RuleBailout
368:
            p 'aaa'
369:
          end
370:
        end
371:
        __dirty_recursive
372:
        @after_push.call(@context) unless @after_push.nil?
373:
        @timers.delete_if do |seconds,what|
374:
          __set_timer(data,seconds,what)
375:
          true
376:
        end
377:
      end
378:
 
379:
      true
380:
    end
381:
  end# }}}
382:
 
383:
  def before_push(&blk)# {{{
384:
    @before_push = blk
385:
  end# }}}
386:
  def after_push(&blk)# {{{
387:
    @after_push = blk
388:
  end# }}}
389:
end