tcontext.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. import random
  5. from tconstants import TConstants as TC
  6. from utils import Utilities as utils
  7. '''
  8. holds a transformation execution context
  9. t the model transformation data
  10. rconfig data from the transformation's RuntimeConfiguration entity,
  11. if any
  12. _expired true when this context's transformation has terminated
  13. _lastStep the last executed transformation step
  14. MTC : ([fname,] [id,] applicationInfo, feedbackInfo)
  15. EC : (step#, applicationInfo, feedbackInfo)
  16. _notApplicable true if all steps in this transformation were N/A '''
  17. class TransformationContext(object) :
  18. def __init__(self,t) :
  19. self.t = t
  20. self._rconfig = None
  21. self._expired = False
  22. self._lastStep = {}
  23. self._notApplicable = True
  24. '''
  25. returns the application information associated with this entire
  26. transformation context '''
  27. def _applicationInfo(self) :
  28. if self._lastStep['applicationInfo'] == TC.FAILED :
  29. return TC.FAILED
  30. elif self._notApplicable :
  31. return TC.NOT_APPLICABLE
  32. else :
  33. return TC.SUCCEEDED
  34. '''
  35. returns the data stored in this context's transformation's
  36. RuntimeConfiguration entity, if any... also remembers it in '_rconfig' for
  37. future reference '''
  38. def getRuntimeConfiguration(self) :
  39. if self._rconfig == None :
  40. mm = '/Formalisms/__Transformations__/Transformation/Transformation/'
  41. for id in self.t['nodes'] :
  42. if self.t['nodes'][id]['$type'] == mm+'RuntimeConfiguration' :
  43. self._rconfig = self.t['nodes'][id]['options']['value']
  44. self._rconfig = (self._rconfig or {})
  45. return self._rconfig
  46. '''
  47. return true if no step has run yet (1st condition), or if the last step's
  48. (which may be a proper last step or {} if the context's transformation
  49. has terminated) feedbackReceived flag is set '''
  50. def isLastStepFeedbackReceived(self) :
  51. return (not self._expired and self._lastStep == {}) or \
  52. 'feedbackReceived' in self._lastStep
  53. '''
  54. returns true if the context's transformation has begun (i.e., the first
  55. step has been taken) '''
  56. def isTransformationUnderWay(self) :
  57. return not self._lastStep == {}
  58. '''
  59. return the next step to run '''
  60. def nextStep(self) :
  61. raise NotImplementedError('implement in subclass')
  62. '''
  63. set the application information of the last step (i.e., whether it was
  64. a) N/A, b) applicable and succeeded or c) applicable and failed '''
  65. def setLastStepApplicationInfo(self,applicationInfo) :
  66. raise NotImplementedError('implement in subclass')
  67. '''
  68. set the feedbackReceived flag of the last step to true (i.e., indicate
  69. that all relevant asworker changelogs have been received and handled '''
  70. def setLastStepFeedbackReceived(self) :
  71. self._lastStep['feedbackReceived'] = True
  72. '''
  73. add 'a' amount of time to total execution time '''
  74. def setLastStepExecTime(self,a):
  75. raise NotImplementedError('implement in subclass')
  76. '''
  77. holds the execution context of a 'Transformation' construct
  78. fname the filename of the transformation model '''
  79. class ModelTransformationContext(TransformationContext) :
  80. def __init__(self,t,fname) :
  81. super(ModelTransformationContext,self).__init__(t)
  82. self.fname = fname
  83. ''' hergin :: motifIntegration '''
  84. self.nextInput = "packetIn"
  85. self.metamodel = TC.TRANSFMM
  86. '''
  87. returns the id of the current step in the transformation model '''
  88. def getCurrentStepId(self) :
  89. if self._lastStep == {} :
  90. assert False, \
  91. "this function shouldn't be called when there is no current step"
  92. else :
  93. return self._lastStep['id']
  94. '''
  95. return the step within this transformation that has its 'isStart'
  96. attribute set to true '''
  97. def _getInitialStep(self) :
  98. for id in self.t['nodes'] :
  99. if 'isStart' in self.t['nodes'][id] and \
  100. self.t['nodes'][id]['isStart']['value'] :
  101. if 'filename' in self.t['nodes'][id] :
  102. return {'fname':self.t['nodes'][id]['filename']['value'],
  103. 'id':id}
  104. else :
  105. return {'id':id}
  106. '''
  107. return the next step to run in this transformation... this is either
  108. the initial step OR a neighbour of the last step... which one of these
  109. neighbours is the next step is determined by the application information
  110. of the said last step
  111. 0. if self._expired is true (i.e., a race condition occurred causing this
  112. context to be called after it terminated but before ptcal.stop()
  113. removed it from ptcal._mtContexts), raise error
  114. 1. if there is no last step, return initial step
  115. 2. filter through edges to find appropriate edge out of last step
  116. a) if none is found, reset lastStep, set self._expired flag, and
  117. return the application information of this entire transformation
  118. context
  119. b) otherwise, return step on the other end of the said edge '''
  120. def nextStep(self) :
  121. if self._expired == True :
  122. raise RuntimeError('can not step in expired mtContext')
  123. elif self._lastStep == {} :
  124. ns = self._getInitialStep()
  125. if ns == None :
  126. return {'$err':'could not find initial transformation step'}
  127. self._lastStep['id'] = ns['id']
  128. return ns
  129. else :
  130. mm = '/Formalisms/__Transformations__/Transformation/Transformation/'
  131. def f(e) :
  132. return e['src'] == self._lastStep['id'] and \
  133. self.t['nodes'][e['dest']]['$type'] == \
  134. mm+'On'+self._lastStep['applicationInfo']
  135. ne = filter(f,self.t['edges'])
  136. if len(ne) == 0 :
  137. ai = self._applicationInfo()
  138. self._lastStep = {}
  139. self._expired = True
  140. return ai
  141. else :
  142. ne = ne[0]
  143. for e in self.t['edges'] :
  144. if e['src'] == ne['dest'] :
  145. if 'filename' in self.t['nodes'][e['dest']] :
  146. self._lastStep = \
  147. {'fname':self.t['nodes'][e['dest']]['filename']['value'],
  148. 'id':e['dest']}
  149. else :
  150. self._lastStep = {'id':e['dest']}
  151. return self._lastStep
  152. raise ValueError('invalid transformation model, dangling '+\
  153. 'On'+self._lastStep['applicationInfo']+' edge')
  154. '''
  155. set the application information of the last step '''
  156. def setLastStepApplicationInfo(self,applicationInfo) :
  157. if applicationInfo == TC.SUCCEEDED :
  158. self._notApplicable = False
  159. self._lastStep['applicationInfo'] = applicationInfo
  160. def setLastStepExecTime(self,a):
  161. ''' to be implemented '''
  162. pass
  163. '''
  164. holds the execution context of an 'Exhaust[Random]' construct
  165. _id the Exhaust[Random]'s id in the transformation model
  166. _randomGen holds a random number generator if this is an ExhaustRandom
  167. _NAs holds the ids of the non-applicable steps in this
  168. Exhaust[Random] '''
  169. class ExhaustContext(TransformationContext) :
  170. def __init__(self,t,id,randomGen=None) :
  171. super(ExhaustContext,self).__init__(t)
  172. self._id = id
  173. self._randomGen = randomGen
  174. self._NAs = set()
  175. '''
  176. return the next step to run in this Exhaust[Random]... this is either
  177. the next step listed in the 'filenames' attribute OR a random not-N/A
  178. step listed in the 'filenames' attribute
  179. 0. if self._expired is true (i.e., a race condition occurred causing this
  180. context to be called after it terminated but before ptcal.stop()
  181. removed it from ptcal._mtContexts), raise error
  182. 1. if all steps are N/A, reset lastStep, set self._expired flag, and
  183. return the application information of this entire transformation
  184. context
  185. 2. if this is an ExhaustRandom, randomly choose a not-N/A step and set
  186. it as self._lastStep
  187. 2. if this is an Exhaust, increment self._lastStep
  188. 3. return self._lastStep '''
  189. def nextStep(self) :
  190. steps = self.t['nodes'][self._id]['filenames']['value']
  191. if self._expired == True :
  192. raise RuntimeError('can not step in expired mtContext')
  193. elif len(steps) == 0 :
  194. return TC.NOT_APPLICABLE
  195. elif len(set(steps)) == len(self._NAs) :
  196. ai = self._applicationInfo()
  197. self._lastStep = None
  198. self._expired = True
  199. return ai
  200. if self._randomGen != None :
  201. notNAs = set(range(0,len(steps))) - self._NAs
  202. r = self._randomGen.choice(list(notNAs))
  203. self._lastStep = {'step#':r}
  204. else :
  205. if self._lastStep == {} :
  206. self._lastStep = {'step#':0}
  207. else :
  208. self._lastStep = {'step#':(self._lastStep['step#']+1)%len(steps)}
  209. return {'fname':steps[self._lastStep['step#']]}
  210. '''
  211. set the application information of the last step
  212. NOTE: on success, we switch the self._notApplicable flag... this flag
  213. indicates whether a rule was succesfully applied within this
  214. transformation context... we also reset self._NAs to indicate
  215. that each step should be run at least once to re-establish its
  216. (non-)applicability '''
  217. def setLastStepApplicationInfo(self,applicationInfo) :
  218. if applicationInfo == TC.SUCCEEDED :
  219. self._notApplicable = False
  220. self._NAs = set()
  221. elif applicationInfo == TC.NOT_APPLICABLE :
  222. self._NAs.add(self._lastStep['step#'])
  223. self._lastStep['applicationInfo'] = applicationInfo