Name: simulation/lib/result.rb 
1:
# Apache License, Version 2.0
2:
#
3:
# Copyright (c) 2013 Juergen Mangler
4:
#
5:
# Licensed under the Apache License, Version 2.0 (the "License");
6:
# you may not use this file except in compliance with the License.
7:
# You may obtain a copy of the License at
8:
#
9:
#     http://www.apache.org/licenses/LICENSE-2.0
10:
#
11:
# Unless required by applicable law or agreed to in writing, software
12:
# distributed under the License is distributed on an "AS IS" BASIS,
13:
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14:
# See the License for the specific language governing permissions and
15:
# limitations under the License.
16:
 
17:
require 'chronic_duration'
18:
 
19:
class Result
20:
  def self.askForInput(head,doc,label)
21:
    ### setting status to asking
22:
    meta = JSON.parse(File.read($dir + "/meta"))
23:
    meta['status'] = "asking"
24:
    File.write($dir + "/meta",JSON.generate(meta))
25:
 
26:
    ### generate question.json
27:
    str = JSON.pretty_generate(:head => head, :doc => doc, :label => label)
28:
    File.write($dir + "/question.json",str)
29:
    sleep 2 until File.stat($dir + "/question.json").size > str.length
30:
 
31:
    ### return result and clean up
32:
    result = JSON.parse(File.read($dir + "/question.json"))["result"]
33:
    File.unlink($dir + "/question.json")
34:
    result
35:
  end
36:
 
37:
  def self.finish
38:
    ### setting status to asking
39:
    meta = JSON.parse(File.read($dir + "/meta"))
40:
    meta['status'] = "finished"
41:
    File.write($dir + "/meta",JSON.generate(meta))
42:
  end
43:
 
44:
  def self.forecast(client,dataelements,endpoints,ep,a,min,avg,max)
45:
    return [404, {}] if endpoints[ep].nil?
46:
    gw, op = endpoints[ep].split('#',2)
47:
    pr, gw = gw.split(/:\/\//)
48:
 
49:
    doc = XML::Smart.open_unprotected(::File.dirname(__FILE__) + '/../resources/template_req.xml')
50:
    doc.register_namespace 'g', 'http://www.fp7-adventure.eu/xmlSchema/Gateways/'
51:
 
52:
    doc.find("/g:gatewayRequest/g:header/g:operationName").each { |e| e.text = op }
53:
    doc.find("/g:gatewayRequest/g:header/g:protocol").each { |e| e.text = pr }
54:
    doc.find("/g:gatewayRequest/g:header/g:target").each { |e| e.text = gw }
55:
    doc.find("/g:gatewayRequest/g:header/g:start_min").each { |e| e.text = (Time.now + min).xmlschema }
56:
    doc.find("/g:gatewayRequest/g:header/g:start_avg").each { |e| e.text = (Time.now + avg).xmlschema }
57:
    doc.find("/g:gatewayRequest/g:header/g:start_max").each { |e| e.text = (Time.now + max).xmlschema }
58:
 
59:
    doc.find("/g:gatewayRequest/g:payload").each do |e|
60:
      a.parameters.each do |k,v|
61:
        if v[0] == "➤"
62:
          vname = v[1..-1]
63:
          v = dataelements[vname]
64:
          if v.nil?
65:
            v = Result::askForInput("Missing Dataelement",File.read(File.dirname(__FILE__) + "/../resources/dataelement.txt"),"Missing \"#{vname}\" for task \"#{a.to_s_nice}\":")
66:
            dataelements[vname] = v
67:
          end
68:
        end  
69:
 
70:
        tmp = JSON.parse(v) rescue v
71:
        if tmp.is_a?(Hash) || tmp.is_a?(Array)
72:
          e.add("g:inputParameter", XmlSimple.xml_out(tmp,'keeproot'=>''), 'encoding' => 'false', 'paramName' => k)
73:
        else
74:
          e.add("g:inputParameter", v, 'encoding' => 'false', 'paramName' => k)
75:
        end  
76:
      end
77:
    end
78:
 
79:
    status, result = client.post Riddl::Parameter::Complex.new("simulationRequest","text/xml",doc.to_s)
80:
    jsonresult = []
81:
    if status == 200
82:
      doc = XML::Smart::string(result[0].value.read)
83:
      doc.register_namespace 'r', 'http://www.fp7-adventure.eu/xmlSchema/Gateways/'
84:
      doc.find("/r:gatewayResponse/r:payload/r:outputData[@paramName='summary']").each do |e|
85:
        res = {}
86:
 
87:
        det = { :prob => e.attributes['probability'], :min => ChronicDuration.parse(e.attributes['min_time']), :max => ChronicDuration.parse(e.attributes['max_time']), :avg => ChronicDuration.parse(e.attributes['avg_time'])}
88:
        if e.text_only?
89:
          sum = XML::Smart::string(e.text)
90:
          sum.root.namespaces.add(nil,'http://www.fp7-adventure.eu/xmlSchema/Gateways/')
91:
        else
92:
          sum = e.children.first.to_doc
93:
        end  
94:
        sum.register_namespace 'r', 'http://www.fp7-adventure.eu/xmlSchema/Gateways/'
95:
        sum.find("/r:summary/r:info/r:info").each do |i|
96:
          res[i.attributes['name'].downcase] = i.attributes['value']
97:
          res[i.attributes['name'].downcase] = (Float(res[i.attributes['name'].downcase]) rescue res[i.attributes['name'].downcase])
98:
        end
99:
        jsonresult << [res, det]
100:
      end  
101:
    end
102:
 
103:
    [status, jsonresult]
104:
  end
105:
 
106:
  def self.manipulate(dataelements,endpoints,result,a)
107:
    return [true, dataelements, endpoints] if a.code.nil?
108:
    client = Riddl::Client.new("http://fp7-adventure.eu:9292",nil)
109:
    resource = client.resource('/')
110:
 
111:
    status, res = resource.post [
112:
      Riddl::Parameter::Simple.new("dataelements", JSON::generate(dataelements)),
113:
      Riddl::Parameter::Simple.new("endpoints", JSON::generate(endpoints)),
114:
      Riddl::Parameter::Simple.new("resultname", "result"),
115:
      Riddl::Parameter::Simple.new("resultvalue", JSON::generate(result)),
116:
      Riddl::Parameter::Simple.new("code", a.code)
117:
    ]
118:
 
119:
    mval = nil
120:
    if status == 200
121:
      id = res[0].value
122:
 
123:
      resource = client.resource('/' + id)
124:
      status, res = resource.get
125:
      if status == 200
126:
        mval = JSON::parse(res[0].value)
127:
      else  
128:
        return false
129:
      end
130:
    else
131:
      return false
132:
    end
133:
 
134:
    return [true, mval['dataelements'], mval['endpoints']]
135:
  end
136:
end
137:
 
138:
class ResultTreeNode
139:
  attr_reader :message, :endpoint, :dataelements, :endpoints, :id
140:
 
141:
  attr_reader :start_min, :start_max, :start_avg
142:
  attr_reader :min, :max, :avg, :prob
143:
 
144:
  def initialize(id,message,endpoint,dataelements,endpoints,start_min,start_avg,start_max,min,avg,max,prob)
145:
    @sub = []
146:
    @message = message
147:
    @endpoint = endpoint
148:
    @dataelements = dataelements
149:
    @endpoints = endpoints
150:
    @id = id
151:
    @start_min = start_min
152:
    @start_avg = start_avg
153:
    @start_max = start_max
154:
    @min = min
155:
    @avg = avg
156:
    @max = max
157:
    @prob = prob.to_f/100
158:
  end
159:
 
160:
  def leaf?
161:
    @sub.empty?
162:
  end
163:
 
164:
  def to_s
165:
    rec_to_s self, 2, self.prob, self
166:
  end
167:
 
168:
  def rec_to_s(what,indent,prob,root)
169:
    coll = ''
170:
    ind = " " * indent
171:
    coll << ind << "Task:         #{what.id}\n"
172:
    coll << ind << "Endpoint(s):  #{what.endpoint.split(/, /).uniq.join(', ')}\n" unless what.endpoint.nil?
173:
    coll << ind << "Result:       #{what.message}\n"
174:
    coll << ind << "Dataelements: #{what.dataelements.pretty_inspect.strip.gsub(/\n/,"\n#{ind + '              '}")}\n"
175:
    coll << ind << "Start:        Min. #{Time.now + what.start_min}, Avg. #{Time.now + what.start_avg}, Max. #{Time.now + what.start_max}\n"
176:
    coll << ind << "Duration:     Min. #{ChronicDuration.output(what.min)}, Avg. #{ChronicDuration.output(what.avg)}, Max. #{ChronicDuration.output(what.max)}\n"
177:
    coll << ind << "Probability:  #{"%0.2f" % what.prob}\n\n"
178:
    if what.leaf?
179:
      coll << ind << "↳ Total Probability: #{"%0.2f" % (prob * what.prob)}\n"
180:
      coll << ind << "  Total Duration:\n"
181:
      coll << ind << "    Min.: #{ChronicDuration.output(what.start_min+what.min-root.start_min)}" << "\n"
182:
      coll << ind << "    Avg.: #{ChronicDuration.output(what.start_avg+what.avg-root.start_avg)}" << "\n"
183:
      coll << ind << "    Max.: #{ChronicDuration.output(what.start_max+what.max-root.start_max)}" << "\n\n"
184:
    end  
185:
    what.each do |s|
186:
      coll << rec_to_s(s,indent+2,prob*what.prob,root)
187:
    end
188:
    coll
189:
  end
190:
 
191:
  def <<(what)
192:
    @sub << what
193:
  end
194:
  
195:
  def each(&what)
196:
    @sub.each do |s|
197:
      what.call s
198:
    end
199:
  end
200:
 
201:
  def each_leaf(&what)
202:
    if leaf?
203:
      what.call self
204:
    else
205:
      rec_leaf(self).each do |s|
206:
        what.call s
207:
      end
208:
    end
209:
  end
210:
 
211:
  def rec_leaf(sub)
212:
    coll = []
213:
    sub.each do |s|
214:
      if s.leaf?
215:
        coll << s
216:
      else
217:
        coll += rec_leaf s
218:
      end
219:
    end
220:
    coll
221:
  end
222:
  private :rec_leaf
223:
end