motifcontext.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. '''This file is part of AToMPM - A Tool for Multi-Paradigm Modelling
  2. Copyright 2011 by the AToMPM team and licensed under the LGPL
  3. See COPYING.lesser and README.md in the root of this project for full details'''
  4. '''
  5. Transformation context for MoTif
  6. Author: Huseyin Ergin (hergin)
  7. Purpose: MoTif integration to AtomPM
  8. '''
  9. import collections
  10. from .pytcore.rules.arule import ARule
  11. from .pytcore.rules.brule import BRule
  12. from .pytcore.rules.bsrule import BSRule
  13. from .pytcore.rules.crule import CRule
  14. from .pytcore.rules.frule import FRule
  15. from .pytcore.rules.lfrule import LFRule
  16. from .pytcore.rules.lqsrule import LQSRule
  17. from .pytcore.rules.lrule import LRule
  18. from .pytcore.rules.lsrule import LSRule
  19. from .pytcore.rules.query import CQuery2
  20. from .pytcore.rules.query import CQuery3
  21. from .pytcore.rules.query import Query
  22. from .pytcore.rules.sequence import Sequence
  23. from .pytcore.rules.srule import SRule
  24. from .pytcore.tcore.messages import Pivots
  25. from .tconstants import TConstants as TC
  26. from .tcontext import TransformationContext
  27. from .utils import Utilities as utils
  28. '''
  29. holds the execution context of a 'Transformation' construct
  30. t
  31. fname the filename of the transformation model '''
  32. class MotifContext(TransformationContext) :
  33. def __init__(self,fname,ptcal):
  34. super(MotifContext,self).__init__(ptcal._transfData[fname])
  35. self.fname = fname
  36. self.metamodel = TC.MOTIFMM
  37. self.pivots=Pivots()
  38. self.totalExecutionTime=0
  39. self.sendAndApplyDeltaFunc = ptcal.sendAndApplyDelta
  40. self.nextInput = "packetIn"
  41. self.compiler = ptcal._compiler
  42. self.ptcal = ptcal
  43. self.rules = {}
  44. self.startStateID = None
  45. for ruleId in self.t['nodes']:
  46. try:
  47. self.loadRule(ruleId)
  48. except Exception as ex:
  49. ruleName = self.t['nodes'][ruleId]['rule']['value']
  50. template = "{0} Exception raised within rule: {1} Message: {2}"
  51. message = template.format(type(ex).__name__, ruleName, str(ex))
  52. raise type(ex)(message) # raise Exception of same type
  53. def loadRule(self, ruleID):
  54. rule = self.ruleIdentifier(self.t['nodes'], ruleID)
  55. if rule is None:
  56. if self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LRule" or \
  57. self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LSRule" or \
  58. self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LFRule" or \
  59. self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LQSRule":
  60. maxIterations = int(self.t['nodes'][ruleID]['maxIterations']['value'])
  61. nested = int(self.t['nodes'][ruleID]['nested']['value'])
  62. outerFirst = True if nested == 0 else False
  63. def f(e):
  64. return e['src'] == ruleID
  65. lruleEdges = list(filter(f, self.t['edges']))
  66. baseEdgeId = None
  67. loopEdgeId = None
  68. for edge in lruleEdges:
  69. if self.t['nodes'][edge['dest']]['$type'] == self.metamodel + "/base":
  70. baseEdgeId = edge['dest']
  71. elif self.t['nodes'][edge['dest']]['$type'] == self.metamodel + "/loop":
  72. loopEdgeId = edge['dest']
  73. def f(e):
  74. return e['src'] == baseEdgeId
  75. baseRuleIds = list(filter(f, self.t['edges']))
  76. baseRuleID = baseRuleIds[0]['dest']
  77. compiledBaseRule = None
  78. if self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LRule" or \
  79. self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LQSRule":
  80. baseRuleName = self.t['nodes'][baseRuleID]['query']['value']
  81. compiledBaseRule = self.compiler.compileRule(None, baseRuleName)
  82. else:
  83. baseRuleName = self.t['nodes'][baseRuleID]['rule']['value']
  84. compiledBaseRule = self.compiler.compileRule(None, baseRuleName)
  85. # baseRule = ARule(compiledBaseRule['lhs'],compiledBaseRule['rhs'],self.sendAndApplyDeltaFunc)
  86. def f(e):
  87. return e['src'] == loopEdgeId
  88. loopRuleIds = list(filter(f, self.t['edges']))
  89. loopRuleID = loopRuleIds[0]['dest']
  90. loopRuleType = self.t['nodes'][loopRuleID]['$type']
  91. if loopRuleType != self.metamodel + "/CRule":
  92. loopRuleName = self.t['nodes'][loopRuleID]['rule']['value']
  93. compiledLoopRule = self.compiler.compileRule(None, loopRuleName)
  94. loopRule = None
  95. if loopRuleType == self.metamodel + "/ARule":
  96. loopRule = ARule(compiledLoopRule['lhs'], compiledLoopRule['rhs'], self.sendAndApplyDeltaFunc)
  97. elif loopRuleType == self.metamodel + "/FRule":
  98. loopRule = FRule(compiledLoopRule['lhs'], compiledLoopRule['rhs'], maxIterations,
  99. self.sendAndApplyDeltaFunc)
  100. elif loopRuleType == self.metamodel + "/SRule":
  101. loopRule = SRule(compiledLoopRule['lhs'], compiledLoopRule['rhs'], maxIterations,
  102. self.sendAndApplyDeltaFunc)
  103. elif loopRuleType == self.metamodel + "/CRule":
  104. ruleName = self.t['nodes'][loopRuleID]['ref']['value']
  105. self.ptcal._transfData[ruleName] = utils.fread('/users/%s/%s' % (self.ptcal.username, ruleName))
  106. motifContext = MotifContext(ruleName, self.ptcal)
  107. loopRule = CRule(motifContext)
  108. if self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LRule":
  109. rule = LRule(compiledBaseRule['lhs'], loopRule, max_iterations=maxIterations)
  110. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LQSRule":
  111. rule = LQSRule(compiledBaseRule['lhs'], loopRule, max_iterations=maxIterations)
  112. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LSRule":
  113. rule = LSRule(compiledBaseRule['lhs'], compiledBaseRule['rhs'], loopRule, outer_first=outerFirst,
  114. sendAndApplyDeltaFunc=self.sendAndApplyDeltaFunc, max_iterations=maxIterations)
  115. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/LFRule":
  116. rule = LFRule(compiledBaseRule['lhs'], compiledBaseRule['rhs'], loopRule, outer_first=outerFirst,
  117. sendAndApplyDeltaFunc=self.sendAndApplyDeltaFunc, max_iterations=maxIterations)
  118. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/BRule" or \
  119. self.t['nodes'][ruleID]['$type'] == self.metamodel + "/BSRule":
  120. def f(e):
  121. return e['src'] == ruleID
  122. bruleEdges = list(filter(f, self.t['edges']))
  123. branchRuleList = []
  124. for edge in bruleEdges:
  125. if self.t['nodes'][edge['dest']]['$type'] == self.metamodel + "/branch":
  126. branchID = edge['dest']
  127. def f(e):
  128. return e['src'] == branchID
  129. branchRuleID = list(filter(f, self.t['edges']))[0]['dest']
  130. rule = self.ruleIdentifier(self.t['nodes'], branchRuleID)
  131. if rule is None and self.t['nodes'][branchRuleID]['$type'] == self.metamodel + "/CRule":
  132. ruleName = self.t['nodes'][branchRuleID]['ref']['value']
  133. self.ptcal._transfData[ruleName] = utils.fread(
  134. '/users/%s/%s' % (self.ptcal.username, ruleName))
  135. motifContext = MotifContext(ruleName, self.ptcal)
  136. rule = CRule(motifContext)
  137. branchRuleList.append(rule)
  138. if self.t['nodes'][ruleID]['$type'] == self.metamodel + "/BRule":
  139. rule = BRule(branchRuleList)
  140. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/BSRule":
  141. maxIterations = int(self.t['nodes'][ruleID]['maxIterations']['value'])
  142. rule = BSRule(branchRuleList, maxIterations)
  143. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/CRule":
  144. rule = self.t['nodes'][ruleID]['ref']['value']
  145. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/Sequence":
  146. sequenceRuleList = []
  147. rulesFile = self.t['nodes'][ruleID]['ref']['value']
  148. self.ptcal._transfData[rulesFile] = utils.fread('/users/%s/%s' % (self.ptcal.username, rulesFile))
  149. rulesOrdered = collections.OrderedDict(sorted(self.ptcal._transfData[rulesFile]['nodes'].items()))
  150. for ruleId in rulesOrdered:
  151. rule = self.ruleIdentifier(rulesOrdered, ruleId)
  152. if rule != None:
  153. sequenceRuleList.append(rule)
  154. else: # TODO decide for CRule
  155. pass
  156. rule = Sequence(sequenceRuleList)
  157. elif self.t['nodes'][ruleID]['$type'] == self.metamodel + "/Start":
  158. self.startStateID = ruleID
  159. rule = None
  160. if rule is not None:
  161. self.rules[ruleID] = {'id': ruleID,
  162. 'name': self.t['nodes'][ruleID]['name']['value'],
  163. 'alias': self.t['nodes'][ruleID]['alias']['value'],
  164. 'rule': rule}
  165. def ruleIdentifier(self,ruleList,ruleId):
  166. rule = None
  167. if ruleList[ruleId]['$type']==self.metamodel+"/ARule":
  168. ruleName = ruleList[ruleId]['rule']['value']
  169. compiledRule = self.compiler.compileRule(None,ruleName)
  170. rule = ARule(compiledRule['lhs'],compiledRule['rhs'],self.sendAndApplyDeltaFunc)
  171. elif ruleList[ruleId]['$type']==self.metamodel+"/QRule":
  172. ruleName = ruleList[ruleId]['query']['value']
  173. compiledRule = self.compiler.compileRule(None,ruleName)
  174. rule = Query(compiledRule['lhs'])
  175. elif ruleList[ruleId]['$type']==self.metamodel+"/FRule":
  176. maxIterations = ruleList[ruleId]['maxIterations']['value']
  177. ruleName = ruleList[ruleId]['rule']['value']
  178. compiledRule = self.compiler.compileRule(None,ruleName)
  179. rule = FRule(compiledRule['lhs'],compiledRule['rhs'],int(maxIterations),self.sendAndApplyDeltaFunc)
  180. elif ruleList[ruleId]['$type']==self.metamodel+"/SRule":
  181. maxIterations = ruleList[ruleId]['maxIterations']['value']
  182. ruleName = ruleList[ruleId]['rule']['value']
  183. compiledRule = self.compiler.compileRule(None,ruleName)
  184. rule = SRule(compiledRule['lhs'],compiledRule['rhs'],int(maxIterations),self.sendAndApplyDeltaFunc)
  185. elif ruleList[ruleId]['$type'] == self.metamodel+"/CQRule2":
  186. ruleName = ruleList[ruleId]['query']['value']
  187. innerRuleName = ruleList[ruleId]['innerQuery']['value']
  188. compiledRule = self.compiler.compileRule(None,ruleName)
  189. compiledInnerRule = self.compiler.compileRule(None,innerRuleName)
  190. innerQuery = Query(compiledInnerRule['lhs'])
  191. rule = CQuery2(compiledRule['lhs'],innerQuery)
  192. elif ruleList[ruleId]['$type'] == self.metamodel+"/CQRule3":
  193. ruleName = ruleList[ruleId]['query']['value']
  194. innerRuleName = ruleList[ruleId]['innerQuery']['value']
  195. secondInnerRuleName = ruleList[ruleId]['secondInnerQuery']['value']
  196. compiledRule = self.compiler.compileRule(None,ruleName)
  197. compiledInnerRule = self.compiler.compileRule(None,innerRuleName)
  198. compiledSecondInnerRule = self.compiler.compileRule(None,secondInnerRuleName)
  199. innerQuery = Query(compiledInnerRule['lhs'])
  200. secondInnerQuery = Query(compiledSecondInnerRule['lhs'])
  201. rule = CQuery3(compiledRule['lhs'],innerQuery,secondInnerQuery)
  202. return rule
  203. def setLastStepExecTime(self,a):
  204. self._lastStep['time'] = a
  205. self.totalExecutionTime += a
  206. '''
  207. returns the id of the current step in the transformation model '''
  208. def getCurrentStepId(self) :
  209. if self._lastStep == {} :
  210. assert False, \
  211. "this function shouldn't be called when there is no current step"
  212. else :
  213. return self._lastStep['id']
  214. '''
  215. Returns the initial step of transformation which is the step after start state
  216. Steps to find initial step:
  217. 1- Find start state id in self.t['nodes']
  218. 2- Find the edge where start is the 'src'
  219. 3- The edge has the initial step as 'dest' after the link between
  220. Structure:
  221. (startID) ----- (linkID) -----> (initialID)
  222. (startID, linkID) is an edge
  223. (linkID, initialID) is another edge
  224. '''
  225. def _getInitialStep(self) :
  226. if self.startStateID==None:
  227. raise RuntimeError('There is no start state in loaded MoTif instance!')
  228. def f(e) :
  229. return e['src'] == self.startStateID
  230. startStateEdges = list(filter(f,self.t['edges']))
  231. initialStepID=None
  232. if len(startStateEdges) == 0 :
  233. raise RuntimeError('Start state is not connected to any other state!')
  234. else:
  235. firstLinkID=startStateEdges[0]['dest']
  236. def f(e) :
  237. return e['src'] == firstLinkID
  238. startStateEdges = list(filter(f,self.t['edges']))
  239. initialStepID=startStateEdges[0]['dest']
  240. if initialStepID in self.rules:
  241. return self.rules[initialStepID]
  242. else:
  243. if self.t['nodes'][initialStepID]['$type']==self.metamodel+"/EndSuccess":
  244. return {'trafoResult':TC.SUCCEEDED,
  245. 'feedbackReceived':'True'}
  246. elif self.t['nodes'][initialStepID]['$type']==self.metamodel+"/EndFail":
  247. return {'trafoResult':TC.FAILED,
  248. 'feedbackReceived':'True'}
  249. '''
  250. return the next step to run in this transformation... this is either
  251. the initial step OR a neighbour of the last step... which one of these
  252. neighbours is the next step is determined by the application information
  253. of the said last step
  254. 0. if self._expired is true (i.e., a race condition occurred causing this
  255. context to be called after it terminated but before ptcal.stop()
  256. removed it from ptcal._mtContexts), raise error
  257. 1. if there is no last step, return initial step
  258. 2. filter through edges to find appropriate edge out of last step
  259. a) if none is found, reset lastStep, set self._expired flag, and
  260. return the application information of this entire transformation
  261. context
  262. b) otherwise, return step on the other end of the said edge
  263. Next step structure
  264. lastStepID --> successID --> nextID
  265. --> failID --> nextID
  266. Steps to find next
  267. 1- Filter edges and get (lastStepID, successID) and (lastStepID,failID) edges
  268. 2- Select success or fail according to _lastStep['applicationInfo']
  269. 3- Find this edge (nextPath, nextStepID) where nextPath is one of the success or fail ids.
  270. '''
  271. def nextStep(self) :
  272. #timeNextStep = clock()
  273. if self._expired == True :
  274. raise RuntimeError('can not step in expired mtContext')
  275. elif self._lastStep == {} :
  276. ns = self._getInitialStep()
  277. if ns == None :
  278. return {'$err':'could not find initial transformation step'}
  279. self._lastStep = ns
  280. return ns
  281. else :
  282. def f(e) :
  283. return e['src'] == self._lastStep['id']
  284. edgesFromLastStep = list(filter(f,self.t['edges']))
  285. if len(edgesFromLastStep) == 0 :
  286. ai = self._applicationInfo()
  287. self._lastStep = {}
  288. self._expired = True
  289. return ai
  290. else :
  291. targetLinkID=None
  292. resString = None
  293. if self._lastStep['applicationInfo'] == TC.SUCCEEDED :
  294. resString = self.metamodel+"/success"
  295. else :
  296. resString = self.metamodel+"/fail"
  297. for edgeLS in edgesFromLastStep:
  298. if self.t['nodes'][edgeLS['dest']]['$type'] == resString:
  299. targetLinkID=edgeLS['dest']
  300. break
  301. def f(e) :
  302. return e['src'] == targetLinkID
  303. nodesAfterLastStep = list(filter(f,self.t['edges']))
  304. nextStepID = nodesAfterLastStep[0]['dest']
  305. if nextStepID in self.rules:
  306. self._lastStep = self.rules[nextStepID]
  307. else:
  308. if self.t['nodes'][nextStepID]['$type']==self.metamodel+"/EndSuccess":
  309. self._lastStep = {'trafoResult':TC.SUCCEEDED,
  310. 'feedbackReceived':'True'}
  311. elif self.t['nodes'][nextStepID]['$type']==self.metamodel+"/EndFail":
  312. self._lastStep = {'trafoResult':TC.FAILED,
  313. 'feedbackReceived':'True'}
  314. #print clock()-timeNextStep
  315. return self._lastStep
  316. '''
  317. set the application information of the last step '''
  318. def setLastStepApplicationInfo(self,applicationInfo) :
  319. if applicationInfo == TC.SUCCEEDED :
  320. self._notApplicable = False
  321. self._lastStep['applicationInfo'] = applicationInfo
  322. def isLastStepFeedbackReceived(self) :
  323. return (not self._expired and self._lastStep=={}) or \
  324. 'feedbackReceived' in self._lastStep