Mercurial > hg > RemoteEditor > REPSessionManager
annotate rep/SessionManager.java @ 385:1fca50ce3508
first-working-version
author | one@firefly.cr.ie.u-ryukyu.ac.jp |
---|---|
date | Mon, 10 Nov 2008 22:18:14 +0900 |
parents | bcdf5476b8e4 |
children | bba62c4ac323 |
rev | line source |
---|---|
266 | 1 |
0 | 2 package rep; |
3 | |
4 import java.io.IOException; | |
5 import java.net.InetSocketAddress; | |
267 | 6 import java.nio.channels.ClosedChannelException; |
0 | 7 |
346 | 8 import org.xml.sax.SAXException; |
9 | |
198 | 10 |
353 | 11 |
337 | 12 import rep.channel.REPLogger; |
133 | 13 import rep.channel.REPSocketChannel; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
14 import rep.gui.CloseButtonEvent; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
15 import rep.gui.SelectButtonEvent; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
16 import rep.gui.SessionManagerEvent; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
17 import rep.gui.SessionManagerEventListener; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
18 import rep.gui.SessionManagerGUI; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
19 import rep.gui.SessionManagerGUIimpl; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
20 import rep.handler.Editor; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
21 import rep.handler.REPNode; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
22 import rep.handler.FirstConnector; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
23 import rep.handler.Forwarder; |
56 | 24 import rep.xml.SessionXMLDecoder; |
45 | 25 import rep.xml.SessionXMLEncoder; |
264 | 26 |
198 | 27 /* |
264 | 28 +-------+--------+--------+-------+--------+---------+------+ |
29 | cmd | session| editor | seqid | lineno | textsiz | text | | |
30 | | id | id | | | | | | |
31 +-------+--------+--------+-------+--------+---------+------+ | |
32 o---------- header section (network order) ----------o | |
33 | |
34 int cmd; kind of command | |
35 int sid; session ID : uniqu to editing file | |
36 int eid; editor ID : owner editor ID = 1。Session に対して unique | |
308 | 37 -1 session manager command |
38 -2 merge command | |
264 | 39 int seqno; Sequence number : sequence number はエディタごとに管理 |
40 int lineno; line number | |
41 int textsize; textsize : bytesize | |
42 byte[] text; | |
198 | 43 */ |
1 | 44 |
384 | 45 public class SessionManager extends ServerMainLoop |
46 implements SessionManagerEventListener { | |
47 SessionList sessionList = new SessionList(); | |
363 | 48 // Known Session Manager List, At most one parent. No parent means master. |
384 | 49 SessionManagerList smList = new SessionManagerList(); |
363 | 50 // Known Editor list. Connected Editor has a channel. |
51 // Session Manager Channel may have dummy editors. | |
384 | 52 EditorList editorList = new EditorList(); |
363 | 53 // Queue limit for debugging purpose. |
384 | 54 static final int packetLimit = 200; |
358 | 55 |
363 | 56 // globalSessionID = SessionManagerID * MAXID + localSessionID |
358 | 57 private static final int MAXID = 10000; |
353 | 58 SessionXMLDecoder decoder = new SessionXMLDecoder(); |
358 | 59 SessionXMLEncoder encoder = new SessionXMLEncoder(); |
363 | 60 // SocketChannel for our parent. At most one parent is allowed. |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
61 private REPNode sm_join_channel; |
363 | 62 // Routing table for session and session manager. |
369 | 63 private RoutingTable routingTable = new RoutingTable(this); |
384 | 64 |
65 static public REPLogger logger = REPLogger.singleton(); | |
66 | |
316 | 67 public static void main(String[] args) throws InterruptedException, IOException { |
384 | 68 int port =ServerMainLoop.DEFAULT_PORT; |
69 int port_s = ServerMainLoop.DEFAULT_PORT; | |
316 | 70 //System.setProperty("file.encoding", "UTF-8"); |
71 if(args.length > 0){ | |
363 | 72 if (args.length!=2) { |
73 logger.writeLog("Usage: sessionManager our_port parent_port"); | |
74 return; | |
75 } | |
316 | 76 port = Integer.parseInt(args[0]); |
77 port_s = Integer.parseInt(args[1]); | |
78 } | |
79 SessionManager sm = new SessionManager(); | |
336 | 80 sm.setReceivePort(port); |
81 sm.setParentPort(port_s); | |
363 | 82 // Ok start main loop |
316 | 83 sm.init(port,new SessionManagerGUIimpl(sm)); |
84 } | |
85 | |
280 | 86 public void init(int port, SessionManagerGUI gui) throws IOException, InterruptedException { |
384 | 87 mainLoop(this, port, gui); |
2 | 88 } |
89 | |
363 | 90 /* |
91 * After loop detection, we give up session manager join. | |
92 */ | |
93 private void cancel_sm_join() { | |
364 | 94 logger.writeLog("Loop detected "+this); |
384 | 95 removeChannel(this, sm_join_channel); |
355 | 96 sm_join_channel=null; |
97 } | |
98 | |
99 | |
100 /** | |
363 | 101 * GUI から、呼ばれて、Session Managerに接続する。 |
355 | 102 * Host 名のSession Manager に SM_JOIN する。自分は、Session を持っていては |
103 * ならない。複数のSession Managerにjoinすることは出来ない。(NATを実装するまでは)。 | |
104 * @param host | |
105 */ | |
378 | 106 public void connectSessionManager(String host, int port) { |
355 | 107 if (sm_join_channel!=null) return; |
108 if (!sessionList.isEmpty()) return; | |
109 if (!smList.isMaster()) return; | |
363 | 110 /* |
111 * IPv6 対応では、複数のアドレスを取って、それのすべてに接続を試す必要が | |
112 * ある。 | |
113 */ | |
1 | 114 InetSocketAddress addr = new InetSocketAddress(host, port); |
115 try { | |
186 | 116 REPSocketChannel<REPCommand> sessionchannel = REPSocketChannel.<REPCommand>create(new REPCommandPacker()); |
1 | 117 sessionchannel.connect(addr); |
337 | 118 while(!sessionchannel.finishConnect()); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
119 REPNode sm = new FirstConnector(this); |
355 | 120 registerChannel(sessionchannel, sm); |
349 | 121 sm_join(sm); |
1 | 122 }catch (IOException e) { |
123 } | |
124 } | |
364 | 125 |
378 | 126 public void connectSessionManager(String host) { |
127 connectSessionManager(host,parent_port); | |
364 | 128 } |
77 | 129 |
363 | 130 /** |
131 * channel に SMCMD_SM_JOIN command を送る。 | |
132 * @param channel | |
133 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
134 private void sm_join(REPNode channel){ |
355 | 135 sm_join_channel = channel; |
122 | 136 //SM_JOINコマンドを生成。 |
77 | 137 REPCommand command = new REPCommand(); |
138 command.setCMD(REP.SMCMD_SM_JOIN); | |
349 | 139 command.setEID(-1); // request Parent SessionManagerID |
140 command.setSID(-1); // request SessionManagerID | |
79 | 141 |
122 | 142 //hostnameをセット。 |
349 | 143 setMyHostName(channel.getLocalHostName()); |
82 | 144 |
355 | 145 String string = myHost; |
77 | 146 command.setString(string); |
147 | |
122 | 148 //SM_JOINコマンドを送信。 |
349 | 149 channel.send(command); |
363 | 150 // ack を受け取ったら、SessionManagerのListに追加。ここではやらない。 |
77 | 151 } |
349 | 152 |
361 | 153 /* |
154 * Select Session from Manager button | |
155 * selected editor is joined editor directly connected to this session | |
156 * manager. | |
157 */ | |
316 | 158 public void selectSession(SelectButtonEvent event) throws IOException { |
250 | 159 int sid = event.getSID(); |
358 | 160 Session session = sessionList.get(sid); |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
161 if (session==null) throw new IOException(); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
162 REPNode editor = event.getEditor(); |
324 | 163 if (editor.hasSession()) return; |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
164 // assert(getSMID(editor.eid)==smList.sessionManagerID()); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
165 // assert(editor.channel!=null); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
166 editor.setSID(sid); // mark as selected |
372 | 167 selectSession0(sid, session, editor.getEID(), editor); |
168 } | |
169 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
170 private void selectSession0(int sid, Session session, int eid, REPNode editor) { |
372 | 171 if (editor.isDirect()&&editor.getEID()==eid) { |
172 selectSession(sid, session, editor.getEID(), editor); | |
173 } else { | |
174 // we don't have this editor, search the editor first. | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
175 REPNode next = routingTable.toSessionManager(getSMID(eid)); |
372 | 176 // pass the select command to the next path. |
177 REPCommand command = new REPCommand(); | |
178 command.setCMD(REP.SMCMD_SELECT0); | |
179 command.setSID(sid); | |
180 command.setEID(eid); | |
181 command.setString(editor.getHost()); | |
182 next.send(command); | |
183 } | |
358 | 184 } |
185 | |
361 | 186 /* |
187 * Select Session Protocol handler | |
363 | 188 * called from GUI or incoming SMCMD_SELECT command. |
361 | 189 */ |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
190 private void selectSession(int sid, Session session, int eid, REPNode editor) { |
372 | 191 if(session.hasOwner()){ |
363 | 192 // we have selected session. |
107 | 193 REPCommand sendCommand = new REPCommand(); |
358 | 194 if (editor.isDirect()&&editor.getEID()==eid) { |
363 | 195 // Found directly connected joined editor. Send join_ack(). |
361 | 196 session.addForwarder(editor); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
197 sendUpdate(session.getSID()); |
358 | 198 sendCommand.setCMD(REP.SMCMD_JOIN_ACK); |
199 } else { | |
363 | 200 // We have a session, but joined editor is on the other sm. |
358 | 201 // SELECT_ACK is sent to the session ring to |
363 | 202 // find out the joined editor. |
358 | 203 sendCommand.setCMD(REP.SMCMD_SELECT_ACK); |
204 } | |
370 | 205 sendCommand.setSID(sid); |
206 sendCommand.string = session.getName(); | |
207 sendCommand.setEID(eid); | |
208 editor.send(sendCommand); | |
107 | 209 }else { |
372 | 210 forwardSelect(sid, session, eid, editor); |
107 | 211 } |
8 | 212 } |
122 | 213 |
372 | 214 private void forwardSelect(int sid, Session session, int eid, |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
215 REPNode editor) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
216 REPNode next; |
372 | 217 // session searching continue... |
218 next = routingTable.toSessionManager(getSMID(sid)); | |
219 // make a forwarding channel here | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
220 REPNode f = createSessionForwarder(sid, next); |
372 | 221 session.setFirstForwarder(f); |
222 session.addForwarder(editor); | |
223 // pass the select command to the next path. | |
224 REPCommand command = new REPCommand(); | |
225 command.setCMD(REP.SMCMD_SELECT); | |
226 command.setSID(sid); | |
227 command.setEID(eid); | |
228 command.setString(editor.getHost()); | |
229 next.send(command); | |
230 } | |
231 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
232 private REPNode createSessionForwarder(int sid, REPNode editor) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
233 REPNode f = new Forwarder(this); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
234 f.setEID(makeID(editorList.newEid())); |
372 | 235 f.setChannel(editor.channel); // incoming channel |
236 f.setHost(myHost); | |
237 f.setSID(sid); | |
238 return f; | |
239 } | |
240 | |
363 | 241 /* |
242 * Create and send UPDATE command. | |
243 */ | |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
244 private void sendUpdate(int sid) { |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
245 REPCommand command = makeREPCommandWithSessionList(REP.SMCMD_UPDATE); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
246 command.setSID(sid); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
247 command.setEID(REP.SM_EID.id); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
248 smList.sendToMaster(command); |
358 | 249 } |
250 | |
363 | 251 /* |
252 * Create new editor in this sessin manager. A dummy editor | |
253 * is created also. | |
254 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
255 public REPNode newEditor(REPSocketChannel<REPCommand> channel) { |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
256 int eid = makeID(editorList.newEid()); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
257 REPNode editor = new Editor(this, eid, channel); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
258 editorList.add(editor); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
259 return editor; |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
260 } |
363 | 261 |
262 /* | |
263 * Create new session. | |
264 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
265 public Session newSession(REPNode master) { |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
266 int sid= makeID(sessionList.newSessionID()); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
267 Session session = new Session(sid, master); |
360 | 268 sessionList.put(sid, session); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
269 return session; |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
270 } |
358 | 271 |
363 | 272 /* |
273 * GUI command interface for close session. | |
274 */ | |
259 | 275 public void closeSession(SessionManagerEvent event) { |
276 Session session = ((CloseButtonEvent) event).getSession(); | |
277 session.closeSession(); | |
278 sessionList.remove(session); | |
279 updateGUI(); | |
280 } | |
281 | |
363 | 282 /* |
283 * Remove editors which has the cannel. | |
284 */ | |
274 | 285 public void remove(REPSocketChannel<REPCommand> channel) { |
358 | 286 int i = 0; |
287 for(Session s:sessionList.values()) { | |
274 | 288 if (s.deleteEditor(channel)) { |
358 | 289 i++; |
274 | 290 } |
291 } | |
358 | 292 assert(i==1); |
274 | 293 // can be other session manager? what should I do? |
294 } | |
295 | |
317 | 296 |
318 | 297 public void remove(Editor editor) { |
358 | 298 Session s = sessionList.get(editor.getSID()); |
362 | 299 if (s==null) { |
300 assert(false); | |
301 editorList.remove(editor); | |
302 } else if (editor.isMaster()) { | |
358 | 303 removeSession(s); |
304 } else { | |
305 s.deleteForwarder(editor); | |
306 editorList.remove(editor); | |
318 | 307 } |
341 | 308 updateGUI(); |
309 } | |
310 | |
311 private void removeSession(Session s0) { | |
358 | 312 s0.remove(this); |
341 | 313 sessionList.remove(s0); |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
314 sendUpdate(s0.getSID()); |
318 | 315 } |
316 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
317 public boolean sessionManage(REPNode forwarder, REPCommand command) throws ClosedChannelException, |
358 | 318 IOException { |
355 | 319 switch(command.cmd){ |
353 | 320 |
321 // Session Manager Command | |
322 | |
323 case SMCMD_JOIN: | |
324 { | |
358 | 325 // first connection or forwarded command |
367 | 326 routingTable.add(forwarder,getSMID(command.eid)); |
358 | 327 if(isMaster()) { |
328 REPCommand ackCommand = new REPCommand(); | |
329 ackCommand.setCMD(REP.SMCMD_JOIN_ACK); | |
330 ackCommand.setEID(command.eid); | |
360 | 331 ackCommand.setSID(command.sid); |
358 | 332 ackCommand.string = command.string; |
333 smList.sendToSlaves(ackCommand); | |
334 registEditor(forwarder,ackCommand); | |
335 } else { | |
336 smList.sendToMaster(command); | |
337 } | |
360 | 338 updateGUI(); |
353 | 339 } |
340 | |
341 break; | |
342 | |
361 | 343 case SMCMD_PUT_ACK: |
366 | 344 if (forwarder.isDirect()) { |
345 // send put_ack to the editor now. | |
346 command.setCMD(REP.SMCMD_PUT_ACK); | |
347 command.string = command.string; | |
348 command.setEID(command.eid); | |
349 command.setSID(command.sid); | |
350 forwarder.send(command); | |
351 } | |
353 | 352 case SMCMD_JOIN_ACK: |
358 | 353 registEditor(forwarder,command); |
360 | 354 updateGUI(); |
353 | 355 break; |
356 | |
357 case SMCMD_PUT: | |
358 { | |
358 | 359 // first connection or forwarded command |
367 | 360 routingTable.add(forwarder,getSMID(command.eid)); |
370 | 361 REPCommand ack = new REPCommand(command); ack.setCMD(REP.SMCMD_PUT_ACK); |
362 if(isMaster()) { | |
371 | 363 // Reached to the top of the tree, multicast the ack. |
370 | 364 smList.sendToSlaves(ack); |
365 registEditor(forwarder,ack); | |
371 | 366 if (forwarder.isDirect()) { |
367 // If put editor on the master, no SMCMD_PUT_ACK is | |
368 // generated. Send ack to the editor now. | |
369 forwarder.send(ack); | |
370 } | |
358 | 371 } else { |
371 | 372 // Pass this to the master. |
358 | 373 smList.sendToMaster(command); |
361 | 374 // registEditor will be done by SMCMD_PUT_ACK |
375 } | |
360 | 376 updateGUI(); |
353 | 377 |
378 } | |
379 break; | |
358 | 380 |
372 | 381 case SMCMD_SELECT0: |
382 /* | |
383 * finding joining editor, do not make the path. | |
384 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
385 REPNode editor = editorList.get(command.eid); |
372 | 386 if (editor==null|| !editor.isDirect()) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
387 REPNode next = routingTable.toSessionManager(getSMID(command.eid)); |
372 | 388 next.send(command); |
389 break; | |
390 } | |
391 // we've found the editor, fall thru. | |
353 | 392 case SMCMD_SELECT: |
361 | 393 { |
372 | 394 /* |
395 * finding active session ring from joined editor. | |
396 */ | |
361 | 397 Session session = sessionList.get(command.sid); |
398 if (session==null) { | |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
399 session = new Session(command.sid, command.string,null); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
400 sessionList.put(command.sid,session); |
361 | 401 } |
372 | 402 // Do not directly addForwarder(forwarder). It may be |
403 // shared among sessions. | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
404 REPNode f = createSessionForwarder(command.sid, forwarder); |
372 | 405 session.addForwarder(f); // f.next is set up here. |
361 | 406 selectSession(command.sid, session, command.eid, forwarder); |
407 } | |
408 break; | |
353 | 409 case SMCMD_SELECT_ACK: |
410 { | |
369 | 411 // Sessionが見つかったので、select したeditorに教える。 |
358 | 412 Session session = sessionList.get(command.sid); |
376 | 413 searchSelectedEditor(command,session.getForwarder(forwarder.channel)); |
353 | 414 } |
358 | 415 break; |
416 | |
353 | 417 case SMCMD_SM_JOIN: |
418 { | |
355 | 419 // SM_JOIN中にSMCMD_SM_JOINが来たら、これはループなので、 |
420 ///自分のSM_JOINを取り消す。 | |
421 if (sm_join_channel!=null) cancel_sm_join(); | |
353 | 422 // SMCMD_SM_JOIN は、master まで上昇する。 |
423 // masterでなければ、自分のparentに転送する。 | |
355 | 424 if(isMaster()) { |
353 | 425 // master であれば、SessionManager IDを決めて、 |
426 // 自分のsmList に登録 | |
377 | 427 registSessionManager(forwarder, command); |
355 | 428 } else { |
429 if (forwarder.sid==-1) { | |
430 // direct link の場合は、識別のために、EIDに直上の | |
431 // smid を入れておく。 | |
432 command.setEID(smList.sessionManagerID()); | |
433 } | |
434 smList.sendToMaster(command); | |
353 | 435 } |
436 } | |
437 break; | |
438 | |
355 | 439 case SMCMD_SM_JOIN_ACK: |
440 send_sm_join_ack(command.eid, command.sid, command); | |
353 | 441 break; |
442 | |
443 case SMCMD_UPDATE: | |
359
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
444 if (!isMaster()) { |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
445 command.setString(mergeUpdate(command)); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
446 // 上に知らせる |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
447 smList.sendToMaster(command); |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
448 break; |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
449 } |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
450 // fall thru |
fa041bae35f1
all code written for distributed session except gather.
kono
parents:
358
diff
changeset
|
451 command.setCMD(REP.SMCMD_UPDATE_ACK); |
353 | 452 case SMCMD_UPDATE_ACK: |
358 | 453 command.setString(mergeUpdate(command)); |
454 // 下に知らせる | |
355 | 455 smList.sendToSlaves(command); |
358 | 456 updateGUI(); |
353 | 457 break; |
458 default: | |
459 return false; | |
460 } | |
461 return true; | |
462 } | |
463 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
464 private void registSessionManager(REPNode forwarder, REPCommand command) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
465 REPNode sm; |
377 | 466 int psid = command.eid; |
467 if (forwarder.sid!=-1) { | |
468 // すでに channelはSessionManager Idを持っていて、 | |
469 // direct link ではないので、 | |
470 // channel を持たないForwarderとして登録する | |
471 sm = new Forwarder(this); | |
472 } else { | |
473 sm = forwarder; | |
474 } | |
475 int sid = smList.addNewSessionManager(sm,command); | |
476 routingTable.add(forwarder,sid); | |
477 | |
478 REPCommand sendCommand = makeREPCommandWithSessionList(REP.SMCMD_SM_JOIN_ACK); | |
479 // command.eid==smList.sesionManagerID() の場合は、 | |
480 // 待っている自分の下のsessionManagerにsidをassignする必要がある。 | |
481 sendCommand.setSID(sid); // new Session manager ID | |
482 // 複数のSM_JOIN_ACKを識別するには、最初にSM_JOINを受け付けた | |
483 // Session manager IDを使う。 | |
484 sendCommand.setEID(psid); | |
485 send_sm_join_ack(psid, sid, sendCommand); | |
486 } | |
487 | |
488 | |
489 void send_sm_join_ack(int psid, int sid,REPCommand sendCommand) { | |
490 if (psid==smList.sessionManagerID()) { | |
491 // 直下のsessionManagerにIDを割り振る必要がある。 | |
492 smList.assignSessionManagerIDtoWaitingSM(sid); | |
493 // ここで smList に一つだけ追加されるので | |
494 // 待っている最初のsm一つにだけ、sm_join_ackが新たに送られる。 | |
495 } | |
496 smList.sendToSlaves(sendCommand); | |
497 } | |
498 | |
372 | 499 /* |
500 * 指定されたeditorがlocalにあるかどうかを調べる。なければ、他に送る。戻って何回も探すことが | |
501 * あり得るので、よろしくない。 | |
502 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
503 private void searchSelectedEditor(REPCommand command, REPNode editor) { |
372 | 504 for(;editor.isDirect();editor = editor.getNextForwarder()) { |
505 if (editor.getEID()==command.eid) { | |
506 // select したeditor を見つけた | |
507 command.cmd=REP.SMCMD_JOIN_ACK; | |
508 editor.send(command); | |
509 return; | |
510 } | |
511 } | |
512 // ここにはありませんでした。 | |
513 editor.send(command); | |
514 } | |
515 | |
355 | 516 |
363 | 517 /** |
518 * UPDATE/UPDATE_ACKにより送られてきたSessionの情報を追加する | |
519 * @param command | |
520 * @return | |
521 * @throws IOException | |
522 */ | |
358 | 523 private String mergeUpdate(REPCommand command) throws IOException { |
524 SessionList receivedSessionList; | |
525 try { | |
526 receivedSessionList = decoder.decode(command.string); | |
527 } catch (SAXException e) { | |
528 throw new IOException(); | |
529 } | |
363 | 530 // 受け取った情報と自分の情報を混ぜる。 |
531 sessionList.merge(receivedSessionList); | |
358 | 532 //XMLを生成。送信コマンドにセット。 |
533 return encoder.sessionListToXML(sessionList); | |
534 | |
535 } | |
536 | |
537 /* | |
538 * id has SessionManager ID part | |
539 */ | |
540 private int makeID(int newid) { | |
541 return newid+smList.sessionManagerID()*MAXID; | |
542 } | |
543 | |
384 | 544 int getSMID(int id) { |
358 | 545 return id/MAXID; |
546 } | |
547 | |
548 | |
361 | 549 /** |
550 * Register Editor to our editorList. No connection is made. | |
551 * @param forwarder Editor to be add | |
552 * @param command | |
553 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
554 public void registEditor(REPNode forwarder,REPCommand command) { |
358 | 555 // make ack for PUT/JOIN. Do not send this to the editor, |
556 // before select. After select, ack is sent to the editor. | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
557 REPNode editor; |
367 | 558 if (getSMID(command.eid)==smList.sessionManagerID()) { |
559 if (forwarder.isDirect()) { | |
560 editor = (Editor)forwarder; | |
561 } else | |
562 return; | |
358 | 563 } else { |
385 | 564 editor = new Editor(this, command.eid); |
358 | 565 } |
566 editor.setName(command.string); | |
567 editor.setSID(command.sid); | |
568 if (!editorList.hasEid(command.eid)) { | |
569 editorList.add(editor); | |
570 } | |
367 | 571 if (command.cmd==REP.SMCMD_PUT_ACK) { |
572 Session session = new Session(command.sid, command.string, editor); | |
573 sessionList.put(command.sid, session); | |
574 } | |
358 | 575 // we don't join ack to the direct linked editor. We |
576 // have to wait select command | |
577 } | |
578 | |
579 | |
355 | 580 private REPCommand makeREPCommandWithSessionList(REP cmd) { |
581 //SessionListからXMLを生成。 | |
582 //joinしてきたSessionManagerに対してACKを送信。 | |
583 REPCommand sendCommand = new REPCommand(); | |
584 sendCommand.setCMD(cmd); | |
358 | 585 sendCommand.setString(encoder.sessionListToXML(sessionList)); |
355 | 586 return sendCommand; |
587 } | |
588 | |
589 | |
590 public boolean isMaster() { | |
591 return smList.isMaster(); | |
592 } | |
593 | |
594 | |
595 public void setSessionManagerID(int sid) { | |
596 smList.setSessionManagerID(sid); | |
597 } | |
598 | |
358 | 599 |
600 public Session getSession(int sid) { | |
601 return sessionList.get(sid); | |
602 } | |
603 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
378
diff
changeset
|
604 public void setParent(REPNode fw) { |
365
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
605 smList.setParent(fw); |
c432755c3555
distributed session debug continue... SELECT/SELECT_ACK loop
kono
parents:
364
diff
changeset
|
606 } |
367 | 607 |
608 public String toString() { | |
609 int myId = 0; | |
610 if (smList!=null) myId = smList.sessionManagerID(); | |
384 | 611 return "rep.SessionManager-"+myId+"@"+super.toString(); |
367 | 612 } |
385 | 613 |
614 public void addWaitingSessionManager(REPNode fw, REPCommand command) { | |
615 smList.addWaitingSessionManager(fw, command); | |
616 } | |
0 | 617 } |