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