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