Mercurial > hg > RemoteEditor > REPSessionManager
changeset 141:6f15a8880ed8
*** empty log message ***
author | pin |
---|---|
date | Wed, 27 Aug 2008 20:43:44 +0900 |
parents | 01062be677e9 |
children | abaf502e6d8f |
files | rep/REP.java rep/REPCommand.java rep/SessionManager.java rep/translater/Translate.java rep/translater/Translater.java rep/translater/TranslaterImp1.java |
diffstat | 6 files changed, 516 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/rep/REP.java Wed Aug 27 20:23:39 2008 +0900 +++ b/rep/REP.java Wed Aug 27 20:43:44 2008 +0900 @@ -13,30 +13,41 @@ public static final int REPCMD_CLOSE_ACK = 12; public static final int REPCMD_REPLACE = 13; public static final int REPCMD_REPLACE_ACK = 14; + public static final int REPCMD_NOP = 15; public static final int SMCMD_JOIN = 41; public static final int SMCMD_JOIN_ACK = 42; - public static final int SMCMD_GET = 43; //obsolete - public static final int SMCMD_GET_ACK = 44; //obsolete + public static final int SMCMD_GET = 43; + public static final int SMCMD_GET_ACK = 44; public static final int SMCMD_PUT = 45; public static final int SMCMD_PUT_ACK = 46; public static final int SMCMD_SELECT = 47; public static final int SMCMD_SELECT_ACK = 48; - public static final int SMCMD_REGISTER = 49; //obsolete - public static final int SMCMD_REGISTER_ACK = 50; //obsolete - public static final int SMCMD_DEREGISTER = 51; //obsolete - public static final int SMCMD_DEREGISTER_ACK= 52; //obsolete + public static final int SMCMD_REGISTER = 49; + public static final int SMCMD_REGISTER_ACK = 50; + public static final int SMCMD_DEREGISTER = 51; + public static final int SMCMD_DEREGISTER_ACK= 52; public static final int SMCMD_QUIT = 53; public static final int SMCMD_QUIT_ACK = 54; - public static final int SMCMD_SESSION = 60; //obsolete - public static final int SMCMD_SESSION_ACK = 61; //obsolete + public static final int SMCMD_SESSION = 60; + public static final int SMCMD_SESSION_ACK = 61; public static final int SMCMD_SM_JOIN = 62; public static final int SMCMD_SM_JOIN_ACK = 63; public static final int SMCMD_UPDATE = 65; public static final int SMCMD_UPDATE_ACK = 66; - public static final int SMCMD_UPDATE_UP = 67; //obsolete - public static final int SMCMD_UPDATE_DOWN = 68; //obsolete - public static final int SMCMD_CH_MASTER = 69; - public static final int SMCMD_CH_MASTER_ACK = 70; public static final int SMCMD_GET_UNDO = 71; public static final int SMCMD_GET_UNDO_ACK = 72; + + public static final int SMCMD_UNDO_REPLACE = 73; + public static final int SMCMD_START_MERGE = 75; + public static final int SMCMD_START_MERGE_ACK = 76; + public static final int SMCMD_END_MERGE = 77; + public static final int SMCMD_QUIT_2 = 78; + + + public static final int MERGE_EID = -2; + public static final int SMCMD_CH_MASTER = 79; + + //public static final int SMCMD_START_MERGE = 73; + //public static final int SMCMD_START_MERGE_ACK = 74; + }
--- a/rep/REPCommand.java Wed Aug 27 20:23:39 2008 +0900 +++ b/rep/REPCommand.java Wed Aug 27 20:43:44 2008 +0900 @@ -1,5 +1,7 @@ package rep; +import remoteeditor.network.REP; + public class REPCommand { public static REPCommand SMCMD_SESSION_JOIN = new REPCommand(REP.SMCMD_SM_JOIN, 0, 0, 0, 0, 0, ""); public int cmd; @@ -9,7 +11,8 @@ public int len; public int lineno; public boolean stat; - + public boolean throughMaster; + public String string; private int textsiz; String host; @@ -23,12 +26,15 @@ this.textsiz = textsiz; this.lineno = lineno; this.string = string; + this.throughMaster = false; + } + public REPCommand(REPCommand cmd){ + this(cmd.cmd, cmd.sid, cmd.eid, cmd.seq, cmd.lineno, cmd.string.length(), new String(cmd.string)); } public REPCommand() { // TODO Auto-generated constructor stub } - public String toString(){ String repCmdString = new String(cmd + "," + sid + "," + eid + "," + seq + "," + lineno + "," + textsiz + "," + string); return repCmdString; @@ -64,9 +70,12 @@ this.port = port; } - public REPCommand clone(){ - REPCommand command = new REPCommand(cmd, sid, eid, seq, lineno, textsiz, new String(string)); - return command; + public void setThroughMaster(boolean f){ + this.throughMaster=f; + } + public void setSEQID(int i) { + // TODO Auto-generated method stub + seq = i; } }
--- a/rep/SessionManager.java Wed Aug 27 20:23:39 2008 +0900 +++ b/rep/SessionManager.java Wed Aug 27 20:43:44 2008 +0900 @@ -116,7 +116,7 @@ if(receivedCommand == null) return; Editor editor; Session session; - REPCommand sendCommand = receivedCommand.clone(); + REPCommand sendCommand = new REPCommand(receivedCommand); REPPacketSend send = new REPPacketSend(channel); //SessionXMLEncoder encoder = new SessionXMLEncoder();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rep/translater/Translate.java Wed Aug 27 20:43:44 2008 +0900 @@ -0,0 +1,150 @@ +package rep.translater; + +import java.util.Iterator; +import java.util.List; + +import rep.REPCommand; +import rep.REP; + +public class Translate { + List <REPCommand> userList; + List <REPCommand> tokenList; + private boolean REP_IGNORE = true; + public int myeid; + + public Translate(){ + + } + + //public Translate(List<REPCommand> userList, List<REPCommand> tokenList){ + // this.userList = userList; + // this.tokenList = tokenList; + //merge(); + //} + + + + public Translate(List<REPCommand> userCmdList, List<REPCommand> tokenCmdList) { + this.userList = userCmdList; + this.tokenList = tokenCmdList; + } + + public void addUserList(REPCommand usercmd){ + userList.add(usercmd); + } + public void addTokenList(REPCommand tokencmd){ + if(tokencmd.eid == myeid){ + tokenList.clear(); + userList.remove(0); + }else{ + tokenList.add(tokencmd); + } + } + + void merge(){ + REPCommand h_pricmd; + REPCommand l_pricmd; +// Iterator userListIterator = userList.iterator(); +// while(userListIterator.hasNext()){ + for(REPCommand userCmd:userList){ + //Iterator tokenListIterator = tokenList.iterator(); + //Rep_Cmd userCmd = (Rep_Cmd)userListIterator.next(); + if(userCmd.stat) continue; /* �폜�����(�\��)��REP�R�}���h�̔�r�͖��� */ + //while(tokenListIterator.hasNext()){ + for(REPCommand tokenCmd:tokenList){ +// Rep_Cmd tokenCmd =(Rep_Cmd)tokenListIterator.next(); + if(tokenCmd.eid == myeid) { + if(tokenCmd.seq == userCmd.seq){ + tokenCmd.stat = REP_IGNORE; + userCmd.stat = REP_IGNORE; + } + } + if(tokenCmd.stat == REP_IGNORE) continue; /* �폜�����(�\��)��REP�R�}���h�̔�r�͖��� */ + if(userCmd.stat == REP_IGNORE) break; + if(userCmd.lineno < tokenCmd.lineno) { /* UsersLineNumber < TokensLineNumber */ + if(userCmd.cmd == REP.REPCMD_INSERT){ + tokenCmd.lineno++; + }else if(userCmd.cmd == REP.REPCMD_DELETE){ + tokenCmd.lineno--; + } + }else if(userCmd.lineno > tokenCmd.lineno){ /* UsersLineNumber > TokensLineNumber */ + if(tokenCmd.cmd == REP.REPCMD_INSERT){ + userCmd.lineno++; + }else if(tokenCmd.cmd == REP.REPCMD_DELETE){ + userCmd.lineno--; + } + }else if(userCmd.lineno == tokenCmd.lineno){ /* UsersLineNumber == TokensLineNumber */ + /* + * �s�ԍ����d�Ȃ��REP�R�}���h�̋������N����̂ŁA + * �ǂ��炩�����Ȃ��Ƃ����Ȃ��B + * uid �����������D��(h_pricmd��)���A + * uid ���傫����(l_pricmd)��ύX����B + */ + if(userCmd.eid < tokenCmd.eid){ + h_pricmd = userCmd; + l_pricmd = tokenCmd; + }else { + h_pricmd = tokenCmd; + l_pricmd = userCmd; + } + if(h_pricmd.cmd == REP.REPCMD_INSERT){ + l_pricmd.lineno++; + }else if(l_pricmd.cmd == REP.REPCMD_REPLACE){ + if(l_pricmd.cmd == REP.REPCMD_INSERT){ + /* h_pricmd ���D�悳��,l_pricmd �͍폜(������)���� */ + l_pricmd.stat = REP_IGNORE; + }else if(l_pricmd.cmd == REP.REPCMD_DELETE){ + /* + * l_pricmd ���ł͂��ł�delete����Ă���̂ŁA + * h_pricmd �� REP_REPLACE_CMD -> REP_INSERT_CMD �֕ύX�B + */ + h_pricmd.cmd = REP.REPCMD_INSERT; + l_pricmd.stat = REP_IGNORE; + } + }else if(h_pricmd.cmd == REP.REPCMD_DELETE){ + if (l_pricmd.cmd == REP.REPCMD_INSERT) { + h_pricmd.lineno++; + } else if(l_pricmd.cmd == REP.REPCMD_REPLACE){ + /* + * h_pricmd ���ł͂��ł�delete����Ă���̂ŁA + * l_pricmd ���� REP_REPLACE_CMD -> REP_INSERT_CMD �֕ύX�B + */ + l_pricmd.cmd = REP.REPCMD_INSERT; + h_pricmd.stat= REP_IGNORE; + } else { /* l_pricmd->cmd == REP_DELETE_LINE_CMD */ + /* + * ����ƍ폜����s���d�Ȃ�̂ŁA + * ����̃R�}���h���ɂ���B + * �����ł͂��łɂ��̍s�͍폜����Ă���B + */ + h_pricmd.stat = REP_IGNORE; + l_pricmd.stat = REP_IGNORE; + break; + } + } + } + } + } +// Iterator userListIterator = userList.iterator(); +// while(userListIterator.hasNext()){ +// //Iterator tokenListIterator = tokenList.iterator(); +// REPCommand userCmd = (REPCommand)userListIterator.next(); +// if(userCmd.stat == REP_IGNORE){ +// userListIterator.remove(); +// } +// } +// +// Iterator tokenListIterator = tokenList.iterator(); +// while(tokenListIterator.hasNext()){ +// REPCommand tokenCmd = (REPCommand)tokenListIterator.next(); +// if(tokenCmd.stat == REP_IGNORE){ +// tokenListIterator.remove(); +// } +// } + } + + public void setMyEID(int myeid2) { + // TODO Auto-generated method stub + myeid = myeid2; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rep/translater/Translater.java Wed Aug 27 20:43:44 2008 +0900 @@ -0,0 +1,33 @@ +package rep.translater; + +import rep.REPCommand; + +public interface Translater { + + /** + * Translate command When the editor send REPCommand to remote editor. + * @param command which the editor want to send. + * @return translated command which should be sent by the editor. + */ + abstract public REPCommand transSendCmd(REPCommand cmd); + + /** + * Inform translater about that the editor receive own command which it sent. + * but in this case, you can use also transReceiveCmd() + * @param command which the editor sent. + */ + abstract public REPCommand[] catchOwnCommand(REPCommand cmd); + + /** + * Translate Command cmd that was received from SeMa. + * @param cmd the command to be translated. + * @return translated command. + */ + abstract public REPCommand[] transReceiveCmd(REPCommand cmd); + + /** + * set the editor's id. + * @param editor's id. + */ + abstract public void setEid(int _eid); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rep/translater/TranslaterImp1.java Wed Aug 27 20:43:44 2008 +0900 @@ -0,0 +1,295 @@ +package rep.translater; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; +import java.util.TreeSet; + +import rep.REPCommand; +import rep.REP; + +public class TranslaterImp1 implements Translater{ + //List <REPCommand> userList; + //List <REPCommand> tokenList; + private LinkedList<REPCommand> sentCmds; + //private LinkedList<REPCommand> unMergedCmds; + private Stack<REPCommand> unMergedCmds; + public int eid; + private int seq; + private LinkedList<REPCommand> undoReplaceList; + private LinkedList<REPCommand> sentMergedList; + private int interruptNumber; + private LinkedList<REPCommand> mergeAgainList; + + public TranslaterImp1(int _eid){ + eid = _eid; + sentCmds = new LinkedList<REPCommand>(); + unMergedCmds = new Stack<REPCommand>(); + undoReplaceList = new LinkedList<REPCommand>(); + mergeAgainList = new LinkedList<REPCommand>(); + sentMergedList = new LinkedList<REPCommand>(); + } + + /** + * Translate cmd When the editor send REPCommand. + * but now, Only adding cmd to the queue is available. + * @param cmd + * @return translated command. + */ + public REPCommand transSendCmd(REPCommand cmd){ + setCmdState(cmd); + sentCmds.add(cmd); + unMergedCmds.push(cmd); + + //マージ中にユーザから割り込みがあった場合 + if(sentMergedList.size() > 0){ + mergeAgainList.add(cmd); + } + + return cmd; + } + /** + * Dequeue command cmd that was returned. + * @param cmd + */ + synchronized public REPCommand[] catchOwnCommand(REPCommand cmd){ + ArrayList<REPCommand> returnCmds = new ArrayList<REPCommand>(); + ArrayList<REPCommand> cmds = new ArrayList<REPCommand>(); + // ringである以上、戻ってきたコマンドは確実にキューsentCmdsの先頭にある事を期待している + REPCommand tmp = sentCmds.poll(); + assert tmp.seq==cmd.seq; + assert cmd.eid==eid; + + //スタック上にあるコマンドを全部undoコマンドにする + while ( !unMergedCmds.isEmpty() ){ + REPCommand cmd0 = unMergedCmds.pop(); + returnCmds.add( createUndo(cmd0) ); + cmds.add(cmd0); + } + + /* 必要な分だけソートして返却用のリストに追加 */ + //if (cmds.size()==0) return null; + returnCmds.addAll( sortCmds(cmds) ); + + /* 残ったコマンドも再び実行させるが、まだマージされてないのでunMergedにも入れる */ + for(int i=0; i<cmds.size(); i++){ + returnCmds.add( cmds.get(i)); + unMergedCmds.push( cmds.get(i)); + } + + //マージ中のエディタからの割り込み検知に使う + sentMergedList.addAll(returnCmds); + + return returnCmds.toArray(new REPCommand[0]); + } + + private REPCommand createUndo(REPCommand cmd){ + //REPCommand retCmd = cmd.clone(); + String str = new String(cmd.string); + REPCommand retCmd = new REPCommand(cmd.cmd, cmd.sid, cmd.eid, cmd.seq, cmd.lineno, str.length(), str); + + retCmd.eid = REP.MERGE_EID; + + if (cmd.cmd==REP.REPCMD_INSERT) retCmd.cmd=REP.REPCMD_DELETE; + else if (cmd.cmd==REP.REPCMD_DELETE) retCmd.cmd=REP.REPCMD_INSERT; + else if (cmd.cmd == REP.REPCMD_REPLACE) retCmd = createUndoReplace(retCmd); + return retCmd; + } + + private REPCommand createUndoReplace(REPCommand cmd) { + for(REPCommand command : undoReplaceList){ + if(command.eid == cmd.eid && command.seq == cmd.seq){ + REPCommand tmp = new REPCommand(command); + tmp.setCMD(REP.REPCMD_REPLACE); + return tmp; + } + } + System.out.println(undoReplaceList); + System.out.println(cmd); + System.out.println(); + return null; + } + + class REPCommandComparator implements Comparator<REPCommand>{ + + public int compare(REPCommand o1, REPCommand o2) { + + if ( o2.lineno > o1.lineno ) return 1; + else if ( o2.lineno < o1.lineno + || o2.eid > o1.eid ) + /* deleteとinsertの場合などはeidによらず、順序を強制する必要があるかも */ + return -1; + + return 1; + } + + } + + private Collection<REPCommand> sortCmds(ArrayList<REPCommand> cmds) { + TreeSet<REPCommand> sortedCmds1 = new TreeSet<REPCommand>(new REPCommandComparator()); + int top; + int prevEid=-1; + int i,j; + + while ( -1 != (top=getPrecedence(cmds, prevEid+1)) ){ + //while ( -1 != (top=getPrecedence(cmds, prevEid)) ){ + REPCommand tmp = cmds.remove(top); + sortedCmds1.add(tmp); + prevEid = tmp.eid; + } + + if(false){ + ArrayList<REPCommand> sortedCmds = new ArrayList<REPCommand>(); + /* lineno の大きい順にソート */ + for (i=0; i<sortedCmds.size(); i++){ + int k=i; + for (j=i+1; j<sortedCmds.size(); j++){ + if ( sortedCmds.get(k).lineno > sortedCmds.get(j).lineno ) continue; + else if ( sortedCmds.get(k).lineno < sortedCmds.get(j).lineno + || sortedCmds.get(k).eid > sortedCmds.get(j).eid ) + /* deleteとinsertの場合などはeidによらず、順序を強制する必要があるかも */ + k=j; + } + REPCommand tmp = sortedCmds.get(i); + sortedCmds.set(i, sortedCmds.get(k)); + sortedCmds.set(k, tmp); + } + } + return sortedCmds1; + } + + /* search cmd. ordering by min EID that is lower lowEid and min SEQ. */ + private int getPrecedence(ArrayList<REPCommand> cmds, int lowEid) { + int cEid, cSeq; + cEid=cSeq=Integer.MAX_VALUE; + int ret=-1; + for (int i=0; i<cmds.size(); i++){ + REPCommand tmp = cmds.get(i); + if ( tmp.eid<lowEid ) continue; + else if ( tmp.eid>cEid ) continue; + else if ( tmp.eid==cEid ) { + if ( tmp.seq>cSeq ) continue; + cSeq=tmp.seq; + ret = i; + } else { /* tmp.eid<cEid */ + cEid = tmp.eid; + cSeq = tmp.seq; + ret = i; + } + //if ( cEid>cmds.get(i) && cmds.get(i)>lowEid ) + } + return ret; + } + + /** + * Translate Command cmd that was received from SeMa. + * @param cmd the command to be translated. + * @return translated commannd. + */ + synchronized public REPCommand[] transReceiveCmd(REPCommand cmd){ + int i=0; + REPCommand cmds[]; + assert (cmd.eid != eid); +// if (cmd.eid==eid){ +// return catchOwnCommand(cmd); +// } + + for (REPCommand cmd0 : unMergedCmds){ + if (cmd0.eid==cmd.eid) i++; + } + + if ( sentCmds.size()<i ){ + //自分のエディタでされた編集コマンドより他のエディタでの編集コマンドのほうが多かった場合NOPを挿入 + //自分のコマンドがないとマージできないのでNOPを挿入 + cmds = new REPCommand[2]; + String str = "NO OPERATION"; + cmds[0] = setCmdState( new REPCommand(REP.REPCMD_NOP, 0, eid, 0, 0, str.length(), str) ); + cmds[1] = cmd; + //unMergedCmds.push(cmds[0]); + unMergedCmds.push(cmd); + sentCmds.add(cmds[0]); + return cmds; + } + + unMergedCmds.push(cmd); /* but.. */ + cmds = new REPCommand[1]; + cmds[0] = cmd; + return cmds; + } + + private REPCommand setCmdState(REPCommand cmd){ + cmd.seq = seq++; + cmd.eid = eid; + return cmd; + } + public void setEid(int _eid){ + eid = _eid; + } + + public Stack<REPCommand> getList() { + // TODO Auto-generated method stub + return unMergedCmds; + } + + public LinkedList<REPCommand> getSentCmds() { + // TODO Auto-generated method stub + return sentCmds; + } + + public void setUndoCommand(REPCommand command) { + // TODO Auto-generated method stub + undoReplaceList.add(command); + } + + public boolean checkMergeConflict(REPCommand command) { + sentMergedList.remove(); + + if(mergeAgainList.size() > 0){ + mergeAgainList.add(command); + if(sentMergedList.size() == 0){ + return true; + } + } + + return false; + } + + public LinkedList<REPCommand> getMergeAgain() { + LinkedList<REPCommand> returnCommand = new LinkedList<REPCommand>(); + for(int i = 0; i < mergeAgainList.size(); i++){ + //eid = REP.MEGE_EID + returnCommand.add(createUndo(mergeAgainList.get(mergeAgainList.size() - i -1))); + } + for(REPCommand command : mergeAgainList){ + if(command.eid == REP.MERGE_EID){ + returnCommand.add(command); + } + } + for(REPCommand command : mergeAgainList){ + if(command.eid == eid){ + command.eid = REP.MERGE_EID; + returnCommand.add(command); + } + } + mergeAgainList.clear(); + sentMergedList = returnCommand; + return returnCommand; + } + + public boolean isFinished() { + if(unMergedCmds.size() > 0) return false; + if(sentMergedList.size() > 0) return false; + if(sentCmds.size() > 0) return false; + return true; + } + + public boolean isMerging() { + // TODO Auto-generated method stub + if(sentMergedList.size() > 0) return true; + return false; + } + +}