root/trunk/RBJabber/RBJabber/SubjectObserver/StateMachine.py

Revision 400, 5.9 kB (checked in by sholloway, 6 years ago)

Integrated SubjectObserver? from old foundation into tree for meantime

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 """State machine implementation using the Subject/Observer design pattern.
23
24 By defining each state as a subject, the state can "call you back" in order to
25 compute complext firing semantics, or when the state is reached.
26 """
27
28 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 #~ Imports
30 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31
32 from CategorySubject import CategorySubject
33 from operator import and_, or_
34
35 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36 #~ Definitions
37 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38
39 class OrStateList(list):
40     def __int__(self):
41         for each in self:
42             if each.GetState():
43                 return 1
44         return 0
45
46     def SetHandled(self):
47         for each in self:
48             if each.GetState():
49                 each.SetHandled()
50    
51 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52
53 class AndStateList(list):
54     def __int__(self):
55         for each in self:
56             if not each.GetState():
57                 return 0
58         if self: return 1
59         else: return 0
60
61     def SetHandled(self):
62         for each in self:
63             if each.GetState():
64                 each.SetHandled()
65    
66 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67
68 class StateSubject(CategorySubject):
69     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
70     #~ Constants / Variables / Etc.
71     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
72
73     value = 0
74     incvalue = 1
75     precondition = None
76
77     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78     #~ Special
79     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
80
81
82     def __init__(self, InfluxsClass=AndStateList, **kw):
83         self.__dict__.update(kw)
84         CategorySubject.__init__(self)
85         self._Influxs = InfluxsClass()
86
87     def __int__(self):
88         return self.GetState()
89
90     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91     #~ Public Methods
92     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
93
94     def GetState(self):
95         return self.value
96
97     def SetState(self, value=None):
98         if value is None: value = self.incvalue
99         if self.value != value:
100             self.value = value
101
102             result = self.PushState()
103
104             return result
105
106     def PushState(self):
107         if self.value and not self._Influxs:
108             self.UpdateObservers(precondition=self.value)
109
110         self.UpdateObservers(state=self)
111
112         return self.GetState()
113
114     def SetHandled(self, handled=1):
115         self.SetState(max(self.value-handled, 0))
116
117     def CheckInfluxs(self, subject, state):
118         if state and not self.value and not self.precondition:
119             self.precondition = int(self._Influxs)
120             if self.precondition:
121                 self.__publishing = 0
122                 self.preconditionlock = self.Lock()
123                 self.UpdateObservers(precondition=self.precondition)
124
125     __publishing = 0
126     def PublishSet(self, subject, state):
127         if self.precondition and not self.__publishing:
128             self.__publishing = 1
129             self._Influxs.SetHandled()
130             self.preconditionlock.SetLock(None)
131             del self.preconditionlock
132             self.precondition = None
133        
134     def AddInflux(self, Influx):
135         self._Influxs.append(Influx)
136         Influx.AddObserver('state', self.CheckInfluxs, priority=-1)
137         Influx.AddObserver('state', self.PublishSet, priority=-2)
138
139     def AddOutflux(self, Outflux):
140         Outflux.AddInflux(self)
141
142 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
143
144 class State(StateSubject):
145     """NOTE: This class is for backward compatability!!!  Please use StateSubject instead."""
146
147     def SetHandled(self, handled=1):
148         pass
149
150     def AddInflux(self, Influx):
151         self._Influxs.append(Influx)
152         # Reverse the order of callable and category for legacy support
153         Influx.AddObserver(self.CheckInfluxs, 'state', priority=-1)
154         Influx.AddObserver(self.PublishSet, 'state', priority=-2)
155
156     def AddObserver(self, callable, category='', **kw):
157         # Reverse the order of callable and category for legacy support
158         category = category or 'precondition'
159         return CategorySubject.AddObserver(self, category, callable, **kw)
160
161 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162 #~ Testing
163 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
164
165 def _Test_StateMachine():
166     from RBFoundation.ContextApply import ContextApply_s_p,ContextApply_0
167     def PrintDescription(State, precondition):
168         print State.__doc__
169         #State.SetState()
170
171     a = State(__doc__="A")
172     a.AddObserver(ContextApply_0(a.SetState))
173     a.AddObserver(PrintDescription)
174     b = State(__doc__="B")
175     b.AddObserver(ContextApply_0(b.SetState))
176     b.AddObserver(PrintDescription)
177     c = State(__doc__="C")
178     c.AddObserver(ContextApply_0(c.SetState))
179     c.AddObserver(PrintDescription)
180     d = State(__doc__="D")
181     d.AddObserver(ContextApply_0(d.SetState))
182     d.AddObserver(PrintDescription)
183
184     b.AddInflux(a)
185     c.AddInflux(b)
186     d.AddInflux(b)
187     d.AddInflux(c)
188
189     a.SetState()
190     assert d.GetState()
191
192 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
193
194 if __name__=='__main__':
195     _Test_StateMachine()
196
Note: See TracBrowser for help on using the browser.