source: geniuswebcore/geniusweb/simplerunner/ClassPathConnectionFactory.py@ 93

Last change on this file since 93 was 90, checked in by Bart Vastenhouw, 3 years ago

Refactor to help reusing partiesserver.

File size: 5.7 KB
Line 
1import importlib
2import re
3from typing import List
4
5from tudelft.utilities.listener.Listener import Listener
6from uri.uri import URI
7
8from geniusweb.actions.Action import Action
9from geniusweb.actions.PartyId import PartyId
10from geniusweb.inform.Inform import Inform
11from geniusweb.party.Party import Party
12from geniusweb.protocol.partyconnection.ProtocolToPartyConn import ProtocolToPartyConn
13from geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory import ProtocolToPartyConnFactory
14from geniusweb.references.Reference import Reference
15from geniusweb.simplerunner.BasicConnection import BasicConnection
16from geniusweb.utils import val
17
18
19class BasicConnectionWithParty (BasicConnection[Action, Inform], ProtocolToPartyConn):
20
21 _id: PartyId
22
23 def __init__(self, reference:Reference ,uri: URI):
24 super().__init__(reference, uri)
25 self._id = PartyId(re.sub("\.", "_", str(uri).replace("pythonpath:", "")))
26
27 def getParty(self)->PartyId :
28 return self._id
29
30 def __repr__(self)->str:
31 return "WP" + super().__repr__()
32
33
34class ConnectionPair:
35 '''
36 Contains the connection from protocol to party and from party to protocol.
37 These two are dependent on each other, and must close together.
38 '''
39 serialcounter = 1 # class variable. Keeps track of used valies.
40 _SCHEME = "pythonpath"
41 _PROTOCOLURI = URI("protocol:protocol")
42
43 _party2protocol: BasicConnection[Inform, Action]
44 _protocol2party: BasicConnectionWithParty
45
46 def __init__(self, reference:Reference ) :
47 '''
48 @param reference the party class path reference4
49 '''
50 # set up the whole other party including the connection to it.
51 classpath = self._getClassPath(reference.getURI())
52 party = self._instantiate(classpath)
53 this=self
54
55 # if call to protocol would fail, we should also close the
56 # protocol2party connection. But we assume that will work fine.
57 class myBC(BasicConnection[Inform, Action]):
58 def __init__(self):
59 super().__init__(reference, ConnectionPair._PROTOCOLURI)
60
61 def close(self):
62 if self.isOpen():
63 super().close()
64 this._protocol2party.close()
65
66 self._party2protocol = myBC()
67
68 # if callback from protocol to party fails, then also close the
69 # other direction.
70 class myBCP(BasicConnectionWithParty):
71 def __init__(self):
72 super().__init__(reference, \
73 URI("pythonpath:" + reference.getURI().getPath()\
74 + "." + str(ConnectionPair.serialcounter)))
75 ConnectionPair.serialcounter += 1
76
77 def close(self):
78 if self.isOpen():
79 super().close()
80 this._party2protocol.close()
81
82
83 self._protocol2party = myBCP()
84
85 class party2protocolListener(Listener[Action]):
86 def notifyChange(self, data: Action):
87 this._protocol2party.notifyListeners(data)
88 self._party2protocol.init(party2protocolListener())
89
90 class protocol2partyListener(Listener[Inform]):
91 def notifyChange(self, data: Inform):
92 this._party2protocol.notifyListeners(data)
93 self._protocol2party.init(protocol2partyListener())
94
95 party.connect(self._party2protocol)
96
97
98 def getOpenConnections(self)->List[BasicConnection] :
99 '''
100 @return the open connections
101 '''
102 open:List[BasicConnection] = []
103 if self._party2protocol.isOpen():
104 open.append(self._party2protocol)
105 if self._protocol2party.isOpen():
106 open.append(self._protocol2party)
107 return open
108
109 def getProtocolToPartyConn(self)->BasicConnectionWithParty :
110 return self._protocol2party
111
112
113 def _getPartyToProtocolConn(self) ->BasicConnection :
114 '''
115 Internal use for testing
116 '''
117 return self._party2protocol
118
119 def _instantiate(self, classpath:str)->Party :
120 '''
121 @param classpath to a full.pythonpath.classname as string.
122 The class must be on the python path.
123 the 'full.pythonpath' must be the module "filename",
124 the "classname" is the name of the class inside the module file.
125 @return instance of the given {@link Party} on the classpath
126 @throws ValueError if the Party can not be instantiated, eg
127 because of a ClassCastException,
128 ClassNotFoundException,
129 IllegalAccessException etc. Such an
130 exception is considered a bug by the
131 programmer, because this is a
132 stand-alone runner.
133 '''
134 print("Connecting with party '" + classpath + "'")
135 try:
136
137 [path, cla] = classpath.rsplit(".",1)
138 mod=importlib.import_module(path)
139 partyclass = getattr(mod, cla)
140 return partyclass()
141 except Exception as e:
142 raise ValueError(
143 "Failed to create connection to party " + classpath,e)
144 importlib
145
146 def _getClassPath(self, uri:URI) -> str:
147 assert isinstance(uri, URI)
148 if self._SCHEME != uri.getScheme():
149 raise ValueError("Required the " + self._SCHEME
150 + " protocol but found " + uri.getScheme())
151 path = uri.getPath()
152 if not path:
153 raise ValueError(
154 "Expected pythonpath not present in " + str(uri))
155 return path
156
157
158
159class ClassPathConnectionFactory (ProtocolToPartyConnFactory):
160 '''
161 A connectionfactory that only accepts URLs of the form
162 <code>pythonpath:org/my/package/class</code>
163 '''
164 _allConnections: List[ConnectionPair] = []
165
166 def connect(self, reference:Reference ) ->ProtocolToPartyConn :
167 '''
168 @param reference the party class path reference4
169 '''
170 connpair = ConnectionPair(reference)
171 self._allConnections.append(connpair)
172 return connpair.getProtocolToPartyConn()
173
174 def connectAll(self, references:List[Reference] ) ->List[ProtocolToPartyConn] :
175 connections:List[ProtocolToPartyConn] = []
176 for partyref in references:
177 connections.append(self.connect(partyref))
178 return connections
179
180 def getOpenConnections(self)->List[BasicConnection] :
181 '''
182 @return list of connections that are still open.
183 '''
184 openconns:List[BasicConnection] = []
185 for connpair in self._allConnections:
186 openconns.extend(connpair.getOpenConnections())
187 return openconns
Note: See TracBrowser for help on using the repository browser.