Mercurial > hg > RemoteEditor > REPSessionManager
comparison test/editortest/REPEditor.java @ 417:267f9748e826
(no commit message)
author | one |
---|---|
date | Wed, 31 Dec 2008 14:52:45 +0900 |
parents | |
children | 7ff127c8ad64 |
comparison
equal
deleted
inserted
replaced
416:b7f42fc75a36 | 417:267f9748e826 |
---|---|
1 package test.editortest; | |
2 | |
3 import java.io.IOException; | |
4 import java.net.InetSocketAddress; | |
5 import java.nio.channels.SelectionKey; | |
6 import java.util.LinkedList; | |
7 import rep.REP; | |
8 import rep.REPCommand; | |
9 import rep.REPCommandPacker; | |
10 import rep.channel.REPSelectionKey; | |
11 import rep.channel.REPSelector; | |
12 import rep.channel.REPSocketChannel; | |
13 | |
14 | |
15 public class REPEditor extends Thread implements REPTextListener{ | |
16 | |
17 private REPSocketChannel<REPCommand> channel; | |
18 REPSelector<REPCommand> selector; | |
19 private boolean running = true; | |
20 private boolean inputLock = false; | |
21 private long timeout = 1; | |
22 private int syncCounter = 0; | |
23 private LinkedList<REPCommand> userCommand = new LinkedList<REPCommand>(); | |
24 private LinkedList<Runnable> runners = new LinkedList<Runnable>(); | |
25 private String name = "test"; | |
26 private int seq; | |
27 private int eid; | |
28 private int sid; | |
29 private REPText repText; | |
30 private boolean hasInputLock; | |
31 private boolean master; | |
32 private boolean syncEnable = true; | |
33 private LogTarget logTarget; | |
34 | |
35 public REPEditor(REPText repText, boolean master){ | |
36 this.repText = repText; | |
37 this.master = master; | |
38 repText.addTextListener(this); | |
39 if(master){ | |
40 userCommand.add(new REPCommand(REP.SMCMD_PUT,0,0,0,0,name +"-file")); | |
41 }else{ | |
42 userCommand.add(new REPCommand(REP.SMCMD_JOIN, 0, 0, 0, 0, name)); | |
43 } | |
44 } | |
45 | |
46 public void textDeleted(REPTextEvent event) { | |
47 Logger.print(event.getText()); | |
48 addUserInput(new REPCommand(REP.REPCMD_DELETE_USER, 0, 0, 0, event.getLineno(), event.getText())); | |
49 } | |
50 | |
51 public void textInserted(REPTextEvent event) { | |
52 Logger.print(event.getText()); | |
53 addUserInput(new REPCommand(REP.REPCMD_INSERT_USER, 0, 0, 0, event.getLineno(), event.getText())); | |
54 } | |
55 | |
56 private void addUserInput(final REPCommand command) { | |
57 Runnable runner = new Runnable(){ | |
58 public void run(){ | |
59 userCommand.add(command); | |
60 timeout = 1; | |
61 } | |
62 }; | |
63 synchronized(runners){ | |
64 runners.add(runner); | |
65 } | |
66 if(selector != null){ | |
67 selector.wakeup(); | |
68 } | |
69 } | |
70 | |
71 public void run(){ | |
72 /* | |
73 * Create Socket and connect to the session manager | |
74 */ | |
75 try { | |
76 channel = REPSocketChannel.<REPCommand>create(new REPCommandPacker()); | |
77 } catch (IOException e) { | |
78 e.printStackTrace(); | |
79 return; | |
80 } | |
81 try { | |
82 InetSocketAddress semaIP = new InetSocketAddress("localhost", 8766); | |
83 while (!channel.connect(semaIP)){ | |
84 Logger.print("SeMa not listen to socket yet, wait"); | |
85 } | |
86 } catch (IOException e) { | |
87 e.printStackTrace(); | |
88 return; | |
89 } | |
90 /* | |
91 * Start editor main loop | |
92 * public REPCommand(REP cmd,int sid,int eid, int seq, int lineno, String string) | |
93 */ | |
94 try { | |
95 mainloop(); | |
96 } catch (IOException e) { | |
97 } | |
98 } | |
99 | |
100 /* | |
101 * Editor main loop with input lock | |
102 */ | |
103 private void mainloop() throws IOException { | |
104 | |
105 channel.configureBlocking(false); | |
106 selector = REPSelector.create(); | |
107 channel.register(selector, SelectionKey.OP_READ); | |
108 while(running) { | |
109 | |
110 synchronized(runners){ | |
111 for(Runnable runner : runners){ | |
112 runner.run(); | |
113 } | |
114 runners.clear(); | |
115 } | |
116 | |
117 if (inputLock) { | |
118 // No user input during merge mode (optional) | |
119 if (selector.select(0)>0) { | |
120 handle(channel.read()); | |
121 } | |
122 continue; | |
123 } else if (selector.select(timeout)<=0) { | |
124 if (syncCounter>0) { | |
125 syncText(); // send the master editor buffer to clients. | |
126 } | |
127 userInput(); | |
128 } | |
129 // selector(timeout) returns 0, but it may contain readable channel.. | |
130 for(REPSelectionKey<REPCommand> key : selector.selectedKeys1()) { | |
131 REPSocketChannel<REPCommand> ch = key.channel1(); | |
132 handle(ch.read()); | |
133 } | |
134 } | |
135 } | |
136 | |
137 private void handle(REPCommand command) { | |
138 Logger.print(logTarget, command); | |
139 if(command == null) return; | |
140 switch(command.cmd){ | |
141 case REPCMD_DELETE: | |
142 if(command.eid != eid){ | |
143 String del = repText.delete(command.lineno); | |
144 command.setString(del); | |
145 } | |
146 forward(command); | |
147 break; | |
148 case REPCMD_INSERT: | |
149 if(command.eid != eid){ | |
150 repText.insert(command.lineno, command.string); | |
151 } | |
152 forward(command); | |
153 break; | |
154 case REPCMD_NOP: | |
155 case REPCMD_INSERT_ACK: | |
156 case REPCMD_DELETE_ACK: | |
157 forward(command); | |
158 break; | |
159 case SMCMD_PUT_ACK: | |
160 sid = command.sid; | |
161 eid = command.eid; | |
162 name += "(eid="+eid+",sid="+sid+")"; | |
163 inputLock = false; | |
164 break; | |
165 case SMCMD_JOIN_ACK : | |
166 sid = command.sid; | |
167 eid = command.eid; | |
168 name += "(eid="+eid+",sid="+sid+")"; | |
169 inputLock = false; | |
170 break; | |
171 case SMCMD_START_MERGE : | |
172 // lock user input during merge (optional) | |
173 inputLock = hasInputLock; | |
174 command.cmd = REP.SMCMD_START_MERGE_ACK; | |
175 send(command); | |
176 break; | |
177 case SMCMD_END_MERGE : | |
178 inputLock = false; | |
179 break; | |
180 case SMCMD_SYNC: | |
181 // start contents sync with newly joined editor | |
182 command.cmd = REP.SMCMD_SYNC_ACK; | |
183 forward(command); | |
184 //if (cmd.eid==eid) { | |
185 if (master && syncEnable ) { | |
186 syncCounter = 1; | |
187 timeout = 1; | |
188 } | |
189 break; | |
190 } | |
191 } | |
192 | |
193 private void userInput() { | |
194 Logger.print(); | |
195 REPCommand command = userCommand.poll(); | |
196 if(command != null){ | |
197 switch(command.cmd){ | |
198 case REPCMD_DELETE_USER: | |
199 send(command); | |
200 break; | |
201 case REPCMD_INSERT_USER: | |
202 send(command); | |
203 break; | |
204 case SMCMD_PUT: | |
205 case SMCMD_JOIN: | |
206 send(command); | |
207 break; | |
208 } | |
209 }else{ | |
210 if(syncCounter == 0){ | |
211 timeout = 0; | |
212 } | |
213 } | |
214 } | |
215 | |
216 private void forward(REPCommand command) { | |
217 REPCommand cmd = new REPCommand(command); | |
218 channel.write(cmd); | |
219 } | |
220 | |
221 private void send(REPCommand command) { | |
222 REPCommand cmd = new REPCommand(command); | |
223 cmd.setSEQID(seq++); | |
224 cmd.setEID(eid); | |
225 cmd.setSID(sid); | |
226 channel.write(cmd); | |
227 } | |
228 | |
229 private void syncText() { | |
230 if(syncCounter>repText.size()){ | |
231 syncCounter = 0; | |
232 }else { | |
233 if(inputLock) return; | |
234 int i = syncCounter - 1; | |
235 REPCommand del = new REPCommand(REP.REPCMD_DELETE_USER, sid, eid, 0, i, repText.get(i)); | |
236 REPCommand ins = new REPCommand(REP.REPCMD_INSERT_USER, sid, eid, 0, i, repText.get(i)); | |
237 send(del); | |
238 send(ins); | |
239 syncCounter++; | |
240 } | |
241 } | |
242 | |
243 public void setLogTarget(LogTarget target){ | |
244 logTarget = target; | |
245 } | |
246 | |
247 } |