Mercurial > hg > RemoteEditor > REPSessionManager
view rep/Editor.java @ 315:20fb70068089
*** empty log message ***
author | kono |
---|---|
date | Mon, 06 Oct 2008 18:58:49 +0900 |
parents | 0585fd2410b8 |
children | 77f443f6dc9f |
line wrap: on
line source
package rep; import java.util.LinkedList; import java.util.List; import rep.channel.REPLogger; import rep.channel.REPSocketChannel; import rep.optimizers.*; import rep.translater.TranslaterImp1; public class Editor { private int eid; // unique id in a session private int sid = -1 ; // globally unique session id private int seq = 0; private REPSocketChannel<REPCommand> myChannel; private String host; private String file; private TranslaterImp1 translater; private List<REPCommand> sentList; // REPCommands we sent to the next editor private List<REPCommand> writeQueue; // REPCommands we are going to send to the next editor private REPCommandOptimizer optimizer; private REPCommand quit2 = null; private REPLogger ns = REPLogger.singleton(); private final int limit=100; public Editor(){ this(true); } public Editor(boolean doOptimize){ setHostAndPort(myChannel); translater = new TranslaterImp1(eid); sentList = new LinkedList<REPCommand>(); writeQueue = new LinkedList<REPCommand>(); if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ else optimizer = new NullOptimizer(); //なにもしないけどOptimizer. } public Editor(int editorNo, REPSocketChannel<REPCommand> channel){ this.eid = editorNo; this.myChannel = channel; translater = new TranslaterImp1(eid); sentList = new LinkedList<REPCommand>(); writeQueue = new LinkedList<REPCommand>(); setHostAndPort(myChannel); } public Editor(REPSocketChannel<REPCommand> channel) { this.myChannel = channel; setHostAndPort(myChannel); translater = new TranslaterImp1(eid); sentList = new LinkedList<REPCommand>(); writeQueue = new LinkedList<REPCommand>(); } enum TranslatorResult { START_MERGE, NEW_COMMAND, MERGE_RETURN, MERGE_AGAIN, INCOMMING_COMMAND, MERGE_END } public TranslatorResult translate(Editor nextEditor, REPCommand command){ if(command.eid == nextEditor.getEID()){ if(checkReturnedCommand(command)){ //エディタからのコマンドが元のエディタに戻ってきた // START_MERGE を送る REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,""); nextEditor.send(cmd); return TranslatorResult.START_MERGE; } else assert(false); } else if(command.eid == eid){ //エディタからの新たな編集コマンド sentList.add(command); assert(sentList.size()<limit); translater.transSendCmd(command); nextEditor.send(command); return TranslatorResult.NEW_COMMAND; }else if(command.eid == REP.MERGE_EID.id){ //マージコマンドが返ってきた if(translater.checkMergeConflict(command)){ //マージ中にエディタからの割り込みがあった場合 if (optimizedSend(translater.getMergeAgain())) { return TranslatorResult.MERGE_AGAIN; } } return isMerging()?TranslatorResult.MERGE_RETURN: TranslatorResult.MERGE_END; }else{ //他のエディタからの編集コマンド translater.transReceiveCmd(nextEditor,command); } return TranslatorResult.INCOMMING_COMMAND; } boolean merge(Editor editor,REPCommand command) { REPCommand prev = translater.prev(); if(prev==null) return false; assert(writeQueue.size()==0); assert(prev.eid==command.eid); //マージして送信 return translater.catchOwnCommand(editor); } boolean checkReturnedCommand(REPCommand command) { if(sentList.size() > 0){ if(sentList.get(0).seq == command.seq){ sentList.remove(0); return true; }else{ System.err.println("Editor.checkReturnedCommand() : command = " + command); assert(false); } } return false; } public boolean doWaitingWrite() { // 一気に送ると、向こう側(Editor)で、dead lock する可能性がある。 // select loop の中で一つ一つ送るしかない。Editor側から割り込まれる可能性も // ある。その時に複数のコマンドを送っていると、どこに割り込まれたかを判断する // ことが出来ない。そこで、一つ一つReturnを確認する必要がある。つまり、 // select loop で送るしかない。 REPCommand cmd; if (writeQueue.size()>0) { cmd = new REPCommand(writeQueue.remove(0)); ns.writeLog("SessionManager write to "+myChannel+" cmd="+cmd); myChannel.write(cmd); return true; } else if (quit2!=null && sentList.size()==0) { myChannel.write(quit2); quit2 = null; return true; } return false; } public void setQuit2(REPCommand cmd) { quit2 = cmd; } private void setHostAndPort(REPSocketChannel<REPCommand> myChannel2) { //host = myChannel2.socket().getRemoteSocketAddress().toString(); } public REPSocketChannel<REPCommand> getChannel() { return myChannel; } public void setHost(String host){ this.host = host; } public String getHost(){ return host; } public int getEID() { return eid; } public void setEID(int eid) { this.eid = eid; translater.setEid(eid); } public String toString(){ return ("Editor eid="+eid+" sid="+sid+" " + host + ":" + file); } public String getName() { return file; } public void setName(String string) { file = string; } public void send(REPCommand command) { writeQueue.add(command); assert(writeQueue.size()<limit); } public void setChannel(REPSocketChannel<REPCommand> channel) { myChannel = channel; } public boolean isMerging() { return translater.isMerging(); } public boolean hasSession() { return sid != -1; } public void setSID(int sessionID) { sid = sessionID; } public int seq() { return seq++; } /** * Sent optimized merged command list * @param output * @return if any sent commands output */ public boolean optimizedSend(LinkedList<REPCommand> output) { List<REPCommand> output1 = optimizer.optimize(output); if (output1.size()==0) return false; for(REPCommand c:output1) { REPCommand m = new REPCommand(c); m.setEID(REP.MERGE_EID.id); m.setSEQID(seq()); writeQueue.add(m); } assert(writeQueue.size()<limit); return true; } }