1
|
1 package rep;
|
|
2
|
122
|
3 import java.util.LinkedList;
|
142
|
4 import java.util.List;
|
349
|
5
|
|
6 import rep.channel.REPSelectionKey;
|
131
|
7 import rep.channel.REPSocketChannel;
|
317
|
8 import rep.handler.PacketSet;
|
224
|
9 import rep.optimizers.*;
|
325
|
10 import rep.translator.Translator;
|
324
|
11 import rep.translator.TranslatorImpl;
|
131
|
12
|
316
|
13 public class Editor extends Forwarder {
|
|
14
|
325
|
15 private Translator translator;
|
316
|
16 private List<REPCommand> sentList = new LinkedList<REPCommand>();
|
315
|
17 // REPCommands we are going to send to the next editor
|
317
|
18 //private REPCommand quit2 = null;
|
|
19 private SessionManager manager;
|
318
|
20 private REPCommand quit2=null;
|
316
|
21
|
317
|
22 public Editor(SessionManager manager,boolean doOptimize,int editorNo){
|
|
23 super(manager);
|
|
24 this.manager = manager;
|
316
|
25 eid = editorNo;
|
326
|
26 REPCommandOptimizer optimizer;
|
224
|
27 if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ
|
|
28 else optimizer = new NullOptimizer(); //なにもしないけどOptimizer.
|
326
|
29 translator = new TranslatorImpl(eid,optimizer);
|
224
|
30
|
155
|
31 }
|
1
|
32
|
317
|
33 public Editor(SessionManager manager,int editorNo, REPSocketChannel<REPCommand> channel){
|
|
34 this(manager,false,editorNo);
|
319
|
35 this.channel = channel;
|
56
|
36 }
|
317
|
37
|
328
|
38 public void translate(REPCommand command){
|
349
|
39
|
|
40 if(command.eid == eid){
|
325
|
41 //エディタからの新たな編集コマンド
|
327
|
42 translator.transSendCmd(command);
|
|
43 sentList.add(new REPCommand(command));
|
325
|
44 assert(sentList.size()<limit);
|
328
|
45 next.send(command);
|
325
|
46 return;
|
315
|
47 }else if(command.eid == REP.MERGE_EID.id){
|
179
|
48 //マージコマンドが返ってきた
|
324
|
49 if(translator.checkMergeConflict(command)){
|
179
|
50 //マージ中にエディタからの割り込みがあった場合
|
326
|
51 translator.getMergeAgain(this);
|
|
52 }
|
|
53 endMerge();
|
349
|
54 }else if(command.eid == next.getEID()){
|
|
55 // 次のEditorで一周するコマンドが来た
|
|
56 if(next==this) return; // singleton case
|
|
57 ((Editor) next).checkReturnedCommand(command);
|
|
58 } else {
|
152
|
59 //他のエディタからの編集コマンド
|
349
|
60 assert (command.eid!=REP.MERGE_EID.id && command.eid!=eid );
|
|
61 if (manager.hasWaitingCommand(channel)) {
|
|
62 // We cannot do this operation before watingCommandQueue.
|
|
63 manager.addWaitingCommand(new PacketSet(channel, this, command));
|
|
64 return;
|
|
65 }
|
317
|
66 if(!isMerging()) {
|
328
|
67 translator.transReceiveCmd(next,command);
|
317
|
68 return;
|
|
69 }
|
328
|
70 manager.addWaitingCommand(new PacketSet(getChannel(), this, new REPCommand(command)));
|
142
|
71 }
|
317
|
72 return;
|
142
|
73 }
|
325
|
74
|
323
|
75 boolean merge(REPCommand command) {
|
313
|
76 //マージして送信
|
324
|
77 return translator.catchOwnCommand(this);
|
142
|
78 }
|
56
|
79
|
325
|
80 void checkReturnedCommand(REPCommand command) {
|
326
|
81 REPCommand prev = sentList.remove(0);
|
327
|
82 if (prev==null || prev.seq != command.seq || prev.eid!=command.eid) {
|
326
|
83 String err = "Editor.checkReturnedCommand() : command = " + command + " prev=";
|
|
84 err += prev==null?"null":prev.toString();
|
337
|
85 SessionManager.logger.writeLog(err);
|
326
|
86 assert(false);
|
142
|
87 }
|
326
|
88
|
325
|
89 // START_MERGE を送る
|
|
90 REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,"");
|
|
91 send(cmd);
|
|
92 // Session Manager 側で、このeditorへの他のeditorからの
|
|
93 // 入力を止めて、merge にそなえる。merge は、eidtor 側から
|
|
94 // ACKが来てから始まる。
|
|
95 translator.startMerge(cmd);
|
|
96 return;
|
74
|
97 }
|
|
98
|
319
|
99 @Override
|
300
|
100 public void setQuit2(REPCommand cmd) {
|
327
|
101 quit2 = cmd;
|
|
102 checkQuit();
|
318
|
103 // do not send quit2 until we received all pending
|
|
104 // command
|
300
|
105 }
|
23
|
106
|
316
|
107 @Override
|
23
|
108 public void setEID(int eid) {
|
|
109 this.eid = eid;
|
324
|
110 translator.setEid(eid);
|
23
|
111 }
|
316
|
112
|
24
|
113 public String toString(){
|
304
|
114 return ("Editor eid="+eid+" sid="+sid+" " + host + ":" + file);
|
24
|
115 }
|
23
|
116
|
164
|
117 public boolean isMerging() {
|
324
|
118 return translator.isMerging();
|
164
|
119 }
|
324
|
120
|
315
|
121
|
164
|
122
|
317
|
123 void endMerge() {
|
324
|
124 if(translator.isMerging()) return;
|
317
|
125 REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,eid,sid,seq(),0,"");
|
326
|
126 send(mergeEnd);
|
|
127 if (quit2!=null) checkQuit();
|
|
128 }
|
|
129
|
|
130 private boolean checkQuit() {
|
|
131 if (sentList.size()==0&&!isMerging()) {
|
|
132 send(quit2);
|
327
|
133 quit2 = null;
|
326
|
134 return true;
|
|
135 }
|
|
136 return false;
|
317
|
137 }
|
|
138
|
319
|
139 @Override
|
|
140 public boolean manage(REPCommand receivedCommand) {
|
330
|
141
|
|
142
|
319
|
143 switch(receivedCommand.cmd){
|
|
144 // Editor Command
|
|
145
|
|
146 case REPCMD_DELETE:
|
|
147 case REPCMD_INSERT:
|
|
148 case REPCMD_NOP:
|
|
149 {
|
328
|
150 translate(receivedCommand);
|
319
|
151 break;
|
|
152 }
|
323
|
153
|
|
154 case SMCMD_START_MERGE_ACK:
|
|
155 {
|
|
156 // マージの処理と次のエディタへコマンドを送信する処理
|
324
|
157 translator.mergeAck();
|
323
|
158 if (!merge(receivedCommand)) {
|
|
159 // nothing to do, send END_MERGE
|
|
160 endMerge();
|
|
161 }
|
|
162 break;
|
|
163 }
|
319
|
164 case SMCMD_QUIT:
|
|
165 {
|
|
166 next.send(receivedCommand);
|
|
167 break;
|
|
168 }
|
|
169 case SMCMD_QUIT_2:
|
|
170 {
|
328
|
171 // QUIT_2 is returned.
|
341
|
172 if (receivedCommand.eid!=eid) {
|
|
173 // stop this editor unless this is the start, starter will stopped
|
|
174 // by QUIT_2_ACK
|
|
175 manager.remove(this);
|
|
176 }
|
|
177 // don't send quit_2 directly to the editor until all pending
|
319
|
178 // merge is processed.
|
341
|
179 next.setQuit2(receivedCommand);
|
|
180 break;
|
|
181 }
|
|
182 case SMCMD_QUIT_2_ACK:
|
|
183 {
|
|
184 manager.remove(this);
|
319
|
185 break;
|
|
186 }
|
|
187 default:
|
|
188 return false;
|
|
189 }
|
|
190 return true;
|
|
191 }
|
|
192
|
349
|
193
|
|
194 @Override
|
|
195 public void handle(REPSelectionKey<REPCommand> key) throws Exception {
|
|
196 REPSocketChannel<REPCommand> channel = key.channel1();
|
|
197 REPCommand command = channel.read();
|
|
198 SessionManager.logger.writeLog("REPHandlerImpl.handle() read : command = " + command +" from "+channel);
|
353
|
199 if (manager.sessionManage(this, command)) return;
|
349
|
200 manage(command);
|
|
201 }
|
|
202
|
|
203 @Override
|
|
204 public void cancel(REPSocketChannel<REPCommand> socketChannel) {
|
|
205 manager.remove(socketChannel);
|
|
206 }
|
1
|
207 }
|