changeset 387:6f356d160e58

IPv6 any address
author one@firefly.cr.ie.u-ryukyu.ac.jp
date Mon, 10 Nov 2008 22:21:52 +0900
parents bba62c4ac323
children 4ec3b70f8f09
files Todo rep/SessionManager.java rep/SessionManagerList.java rep/gui/RPanel.java rep/handler/Dispatcher.java rep/handler/Editor.java rep/handler/FirstConnector.java rep/handler/Forwarder.java rep/handler/NullForwarder.java rep/handler/REPNode.java rep/xml/SessionXMLDecoder.java test/RepCommandOptimizeTest.java test/Text.java test/XMLTest.java test/sematest/TestEditor.java
diffstat 15 files changed, 201 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/Todo	Mon Nov 10 22:19:34 2008 +0900
+++ b/Todo	Mon Nov 10 22:21:52 2008 +0900
@@ -1,4 +1,33 @@
+Sun Oct 26 17:36:40 JST 2008
+Todo: (kono)
+GUI のEditorの方が、どれがどれだか、さっぱりわからない。
+せめて、sessionを持っているかとか出ないとだめっぽい。
+なんか、NO_NAMEってのが最初に出るらしい。なんだ?
+
+Sun Oct 26 14:33:51 JST 2008
+Todo: (kono)
+quit/close 処理が間違っているらしい。
+
+Sat Oct 25 10:52:05 JST 2008
+Todo: (kono)
+Editorからのmutli-sessoin の扱い、TestEditor でのmulti-session
+の実装。REPNode.handle の中でreadしちゃうと、handle 間での処理
+の引き渡しが出来ない。handlerの切替えにkeyは必要。
+
+一つのeditorの中で、同じsessionに複数selectすると、コマンドを
+判定出来なくなる。今でも、新しくchannelを開けるなら複数セッション
+をselectすることは可能。channelで識別しているので。
+新しいeditorが作られてしまうので、ダメなケースの判定は、直接接続し
+ているSMでしか出来ない。と言うことは、selectのcancelのprotocolが
+必要らしい。それは、結構、面倒。command に source editor id を
+付けてやれば良いのだが...
+
+Todo: (kono)
+text editor のバッファが増えるバグがあるらしい。
+    Done: たぶん、quit/quit2が動いてない。close の処理のがまずいせい。
+
 Fri Oct 24 19:00:50 JST 2008
+Note:
 	XML に editor がselectされているかどうかのflagがあった方が良い。
 	現状では、update はなんにも役に立たない。
 	
@@ -12,7 +41,9 @@
 
 Todo: (kono)
 やっぱり、END_MERGEが繰り返し出るバグがあるらしい。
-    Done: Thu Oct 23 10:12:27 JST 2008 merge confilict 時にmode setを忘れてました。
+    Done: Thu Oct 23 10:12:27 JST 2008 merge confilict 時にmode setを
+         忘れてました。
+         結局、flag を入れて対症療法しました。
 
 Wed Oct 22 02:31:27 JST 2008
 
@@ -22,12 +53,13 @@
 だが... やっぱり、dummy editor ではなくて、専用のものを作らないと
 だめ?
 	Done: Wed Oct 22 02:56:30 JST 2008 
-	ちょっとあれだが、next がdirecgtでない場合を判断して、向こうのforwarder側で
-	処理するのが簡単らしい。
+	ちょっとあれだが、next がdirecgtでない場合を判断して、向こうの
+        forwarder側で処理するのが簡単らしい。
 	
 Todo: (kono)
 Select後のupdateを流してないので、他の人が、そのsessionがselectされたのを
 知り得ない。なので、複数のjoin_ackがありえる。
+	Done: Sun Oct 26 17:39:05 JST 2008
 
 Mon Oct 20 16:38:39 JST 2008
 
--- a/rep/SessionManager.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/SessionManager.java	Mon Nov 10 22:21:52 2008 +0900
@@ -51,7 +51,7 @@
 	// Session Manager Channel may have dummy editors.
 	EditorList editorList = new EditorList();
 	// Queue limit for debugging purpose.
-	static final int packetLimit = 200;
+	static final int packetLimit = 400;
 
 	// globalSessionID = SessionManagerID * MAXID + localSessionID
 	private static final int MAXID = 10000;
@@ -118,7 +118,7 @@
 			REPSocketChannel<REPCommand> sessionchannel = REPSocketChannel.<REPCommand>create(new REPCommandPacker());
 			sessionchannel.connect(addr);
 			while(!sessionchannel.finishConnect());
-			REPNode sm = new FirstConnector(this);
+			REPNode sm = new FirstConnector(this,sessionchannel);
 			registerChannel(sessionchannel, sm);
 			sm_join(sm);
 		}catch (IOException e) {
@@ -208,9 +208,9 @@
 	}
 
 	private REPNode createSessionForwarder(int sid, REPNode editor) {
-		REPNode f = new Forwarder(this);
+		REPNode f = new Forwarder(this,editor.channel);
 		f.setEID(makeID(editorList.newEid()));
-		f.setChannel(editor.channel); // incoming channel
+		// f.setChannel(editor.channel); // incoming channel
 		f.setHost(myHost);
 		f.setSID(sid);
 		return f;
@@ -237,7 +237,7 @@
 	 */
 	public REPNode newEditor(REPSocketChannel<REPCommand> channel) {
 		int eid =  makeID(editorList.newEid());
-		REPNode editor = new Editor(this, eid, channel);
+		REPNode editor = new Editor(eid, this, channel);
 		editorList.add(editor);
 		return editor;
 	}
@@ -448,7 +448,7 @@
 		// すでに channelはSessionManager Idを持っていて、
 		// direct link ではないので、
 		// channel を持たないForwarderとして登録する
-			sm = new Forwarder(this);
+			sm = new Forwarder(this,null);
 		} else {
 			sm = forwarder;
 		}
@@ -547,7 +547,7 @@
 			} else 
 				return;
 		} else {
-			editor = new Editor(this, command.eid);
+			editor = new Editor(manager, command.eid);
 		}
 		editor.setName(command.string);
 		editor.setSID(command.sid);
--- a/rep/SessionManagerList.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/SessionManagerList.java	Mon Nov 10 22:21:52 2008 +0900
@@ -13,7 +13,7 @@
 	private static final long serialVersionUID = 1L;
 	private int mySMID=0;
 	private int smid_root=0;
-	private REPNode parent=new NullForwarder(null);
+	private REPNode parent=new NullForwarder(null,null);
 	private LinkedList<REPNode> waiting= new LinkedList<REPNode>();
 
 
--- a/rep/gui/RPanel.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/gui/RPanel.java	Mon Nov 10 22:21:52 2008 +0900
@@ -106,9 +106,12 @@
 			
 		}else if(event.getSource() == selectButton){
 			//System.out.println("RPanel.actionPerformed() : editorSelectedRow = " + editor_table.getSelectedRow());
+			int selectedSession = session_table.getSelectedRow();
+			if (selectedSession<0) return;  // no sessin is selected
+			int selectedEditor = editor_table.getSelectedRow();
 			listener.buttonPressed(
-					new SelectButtonEvent(editorList.get(editor_table.getSelectedRow()),
-					sessionList.get(session_table.getSelectedRow())));
+					new SelectButtonEvent(editorList.get(selectedEditor),
+					sessionList.get(selectedSession)));
 		}else if(event.getSource() == closeButton){
 			listener.buttonPressed(new CloseButtonEvent(sessionList.get(session_table.getSelectedRow()), listener));
 		}
--- a/rep/handler/Dispatcher.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/handler/Dispatcher.java	Mon Nov 10 22:21:52 2008 +0900
@@ -17,8 +17,10 @@
  */
 public class Dispatcher extends Forwarder {
 
-	public Dispatcher(SessionManager manager) {
-		super(manager);
+
+	public Dispatcher(SessionManager manager,
+			REPSocketChannel<REPCommand> channel) {
+		super(manager, channel);
 	}
 
 	public void setQuit2(REPCommand cmd) {
@@ -35,14 +37,13 @@
 	}
 	
 
-	public void handle(REPSelectionKey<REPCommand> key) throws IOException {
+	@Override
+	public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException {
 		/*
 		 * SessionManagerから来たコマンドは、Editor関係のコマンドは、
 		 * sessionとeidを判定して、そのeditorにforwardしてやれば良い。
 		 * 残りは、manager.manage() で処理する。
 		 */
-		REPSocketChannel<REPCommand> channel = key.channel1();
-		REPCommand command = channel.read();
 		ServerMainLoop.logger.writeLog("REPHandlerImpl.handle() : command = " + command);
 		if (manager.sessionManage(this, command)) return;
 		
--- a/rep/handler/Editor.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/handler/Editor.java	Mon Nov 10 22:21:52 2008 +0900
@@ -16,28 +16,26 @@
 public class Editor extends Forwarder {
 
 	private Translator translator;
+	// REPCommands we are going to send to the next editor
 	private List<REPCommand> sentList = new LinkedList<REPCommand>();
-	// REPCommands we are going to send to the next editor
-	//private REPCommand quit2 = null;
-	private SessionManager manager;
 	private REPCommand quit2=null;
+	private boolean merging;
 	static final boolean doOptimize = true;
 
 	public Editor(SessionManager manager,int editorNo){
-		super(manager);
-		this.manager = manager;
+		// no translator case
+		super(manager, null);
+	}
+
+	public Editor(int editorNo, SessionManager manager,REPSocketChannel<REPCommand> channel){
+		super(editorNo,manager,channel);
 		eid = editorNo;
 		REPCommandOptimizer optimizer;
 		if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ
 		else            optimizer = new NullOptimizer();         //なにもしないけどOptimizer.
 		translator = new Translator(eid,optimizer);
-		
 	}
-
-	public Editor(SessionManager manager,int editorNo, REPSocketChannel<REPCommand> channel){
-		this(manager,editorNo);
-		this.channel = channel;
-	}
+	
 
 	public void translate(REPCommand command){
 
@@ -99,6 +97,7 @@
 		//    送らないで良い場合もある?
 		REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,"");
 		send(cmd);
+		merging = true;
 		// Session Manager 側で、このeditorへの他のeditorからの
 		// 入力を止めて、merge にそなえる。merge は、eidtor 側から
 		// ACKが来てから始まる。
@@ -117,7 +116,8 @@
 	@Override
 	public void setEID(int eid) {
 		this.eid = eid;
-		translator.setEid(eid);
+		if (translator!=null)
+			translator.setEid(eid);
 	}
 	
 	public String toString(){
@@ -131,9 +131,12 @@
 	
 
 	void checkEndMerge() {
-		if(translator.isMerging()) return;
-		REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,eid,sid,seq(),0,"");
-		send(mergeEnd);				
+		if (merging) {
+			if(translator.isMerging()) return;
+			REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,eid,sid,seq(),0,"");
+			send(mergeEnd);
+			merging = false;
+		}
 		if (quit2!=null) checkQuit();
 	}
 
@@ -147,17 +150,17 @@
 	}
 
 	@Override
-	public boolean manage(REPCommand receivedCommand) {
+	public boolean manage(REPCommand command) {
 		
 		
-		switch(receivedCommand.cmd){
+		switch(command.cmd){
 		// Editor Command
 		
 		case REPCMD_DELETE:
 		case REPCMD_INSERT:
 		case REPCMD_NOP:
 		{
-			translate(receivedCommand);
+			translate(command);
 			break;
 		}
 
@@ -165,7 +168,7 @@
 		{
 			// マージの処理と次のエディタへコマンドを送信する処理
 			translator.mergeAck();
-			if (!merge(receivedCommand)) {
+			if (!merge(command)) {
 				// nothing to do, send END_MERGE
 				checkEndMerge();
 			}
@@ -174,19 +177,19 @@
 		
 		case SMCMD_SYNC:
 			if (isMaster()) 
-				send(receivedCommand);
+				send(command);
 			else
-				next.send(receivedCommand);
+				next.send(command);
 			
 		case SMCMD_QUIT:
 		{
-			next.send(receivedCommand);
+			next.send(command);
 			break;
 		}
 		case SMCMD_QUIT_2:
 		{
 			// QUIT_2 is returned.
-			if (receivedCommand.eid!=eid) {
+			if (command.eid!=eid) {
 				// stop this editor unless this is the start, starter will stopped
 				// by QUIT_2_ACK
 				manager.remove(this);
@@ -195,9 +198,9 @@
 			// merge is processed.
 			//   this does not work in distributed case.
 			if (next.isDirect())
-				next.setQuit2(receivedCommand);
+				next.setQuit2(command);
 			else
-				next.send(receivedCommand);
+				next.send(command);
 			break;
 		}
 		case SMCMD_QUIT_2_ACK:
@@ -213,10 +216,17 @@
 	
 
 	@Override
-	public void handle(REPSelectionKey<REPCommand> key) throws IOException {
-		REPSocketChannel<REPCommand> channel = key.channel1();
-		REPCommand command = channel.read();
+	public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException {
 		ServerMainLoop.logger.writeLog("REPHandlerImpl.handle() read : command = " + command +" from "+channel);
+		if (command.cmd==REP.SMCMD_JOIN||command.cmd==REP.SMCMD_PUT) {
+			assert false;
+			// 若干問題があるらしい
+			next = new Forwarder(manager,next.channel);
+			REPNode first = new FirstConnector(manager,channel);
+			first.handle(command, key);
+			key.attach(new Dispatcher(manager,channel));
+			return;
+		}
 		if (manager.sessionManage(this, command)) return;
 		manage(command);
 	}
--- a/rep/handler/FirstConnector.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/handler/FirstConnector.java	Mon Nov 10 22:21:52 2008 +0900
@@ -13,15 +13,19 @@
 
 public class FirstConnector extends Forwarder {
 
-	public FirstConnector(SessionManager manager) {
-		super(manager);
+	
+
+	public FirstConnector(SessionManager manager,
+			REPSocketChannel<REPCommand> channel) {
+		super(manager,channel);
 	}
-	
+
 	public void cancel(REPSocketChannel<REPCommand> socketChannel) {
 		manager.remove(socketChannel);
 	}
 
-	public void handle(REPSelectionKey<REPCommand> key) throws IOException {
+	@Override
+	public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException {
 		/*
 		 * 接続要求は、EditorかSlave Editorで、
 		 *    join, put, sm_join
@@ -29,8 +33,6 @@
 		 *      sm_join_ack
 		 */
 		REPNode fw;
-		REPSocketChannel<REPCommand> channel = key.channel1();
-		REPCommand command = channel.read();
 		ServerMainLoop.logger.writeLog("FirstConnector: command = " + command);
 		switch(command.cmd) {
 		case SMCMD_JOIN: 
@@ -63,14 +65,14 @@
 		}
 		case SMCMD_SM_JOIN:
 		{
-			fw = new Dispatcher(manager); // FirstConnector?
+			fw = new Dispatcher(manager,channel); // FirstConnector?
 			manager.addWaitingSessionManager(fw, command);
 			break;
 		}
 		case SMCMD_SM_JOIN_ACK:
 			manager.setSessionManagerID(command.sid);
 			manager.afterConnect();
-			fw = new Dispatcher(manager);
+			fw = new Dispatcher(manager,channel);
 			manager.setParent(fw);
 			break;
 		default: throw new IOException();
--- a/rep/handler/Forwarder.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/handler/Forwarder.java	Mon Nov 10 22:21:52 2008 +0900
@@ -21,11 +21,15 @@
 	// REPCommands we sent to the next editor
 	final int limit=100; // debugging purpose, assert check only
 	final REPLogger ns = REPLogger.singleton();
-	SessionManager manager;
-	public REP mode = null;
-	
-	public Forwarder(SessionManager manager) {
-		this.manager = manager;
+
+	public Forwarder(SessionManager manager,
+			REPSocketChannel<REPCommand> channel) {
+		super(manager,channel);
+	}
+
+	public Forwarder(int editorNo, SessionManager manager,
+			REPSocketChannel<REPCommand> channel) {
+		super(editorNo,manager,channel);
 	}
 
 	public int seq() {
@@ -81,11 +85,13 @@
 		return channel.getLocalHostName();
 	}
 
+	@Override
 	public void cancel(REPSocketChannel<REPCommand> socketChannel) {
 		manager.remove(socketChannel);
 	}
 
-	public void handle(REPSelectionKey<REPCommand> key) throws IOException {
+	@Override
+	public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException {
 		assert false;
 	}
 
--- a/rep/handler/NullForwarder.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/handler/NullForwarder.java	Mon Nov 10 22:21:52 2008 +0900
@@ -14,33 +14,43 @@
  */
 public class NullForwarder extends Forwarder {
 
-	public NullForwarder(SessionManager manager) {
-		super(manager);
+
+	public NullForwarder(SessionManager manager,
+			REPSocketChannel<REPCommand> channel) {
+		super(manager, channel);
 	}
-
+	
+	@Override
 	public void send(REPCommand command) {
 		
 	}
+	
+	@Override
 	public void cancel(REPSocketChannel<REPCommand> socketChannel) {
 
 	}
 
-	public void handle(REPSelectionKey<REPCommand> key) throws IOException {
+	@Override
+	public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException {
 
 	}
 
+	@Override
 	public boolean manage(REPCommand command) {
 		return true;
 	}
 
+	@Override
 	public boolean isEditor() {
 		return false;
 	}
 	
+	@Override
 	public boolean isForwarder() {
 		return false;
 	}
 
+	@Override
 	public boolean isDirect() {
 		return false;
 	}
--- a/rep/handler/REPNode.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/handler/REPNode.java	Mon Nov 10 22:21:52 2008 +0900
@@ -5,6 +5,7 @@
 import rep.REP;
 import rep.REPCommand;
 import rep.Session;
+import rep.SessionManager;
 import rep.channel.REPSelectionKey;
 import rep.channel.REPSocketChannel;
 
@@ -28,14 +29,21 @@
 	public REP mode;
 	public REPSocketChannel<REPCommand> channel;
 	public REPNode next;
+	public SessionManager manager;
 	
 	public REPNode() {
 		
 	}
-	
-	public REPNode(int eid, REPSocketChannel<REPCommand> channel) {
+
+	public REPNode(int eid, SessionManager manager, REPSocketChannel<REPCommand> channel) {
 		this.eid = eid;
 		this.channel = channel;
+		this.manager = manager;
+	}
+	
+	public REPNode(SessionManager manager, REPSocketChannel<REPCommand> channel) {
+		this.channel = channel;
+		this.manager = manager;
 	}
 
 	public String getName() {
@@ -94,7 +102,7 @@
 		if (host==null) host = editor.host;
 	}
 
-	public abstract void handle(REPSelectionKey<REPCommand> key) throws IOException;
+	public abstract void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException;
 
 
 	public abstract void cancel(REPSocketChannel<REPCommand> channel1) ;
--- a/rep/xml/SessionXMLDecoder.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/rep/xml/SessionXMLDecoder.java	Mon Nov 10 22:21:52 2008 +0900
@@ -84,15 +84,17 @@
 					Element elementFile = (Element) nodelistEditorFile.item(0); 
 					String file = elementFile.getFirstChild().getNodeValue();
 					
-					Editor editor = new Editor(null, 0);
-					editor.setHost(host);/* editor.setPort(port)*/; editor.setName(file); editor.setEID(Integer.parseInt(eid)); 
+					int id = Integer.parseInt(eid); 
+					Editor editor = new Editor(null, id);
+					editor.setHost(host);/* editor.setPort(port)*/; editor.setName(file); 
 					session = new Session(sid, editor);
 					session.addEditor(editor);
 					sessionlist.put(sid,session);
 					
 				}else {
-					Editor editor = new Editor(null, 0);
-					editor.setHost(host);/* editor.setPort(port)*/; editor.setName(null); editor.setEID(Integer.parseInt(eid));
+					int id = Integer.parseInt(eid);
+					Editor editor = new Editor(null, id);
+					editor.setHost(host);/* editor.setPort(port)*/; editor.setName(null);
 					if(session != null){
 						session.addEditor(editor);
 					}
--- a/test/RepCommandOptimizeTest.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/test/RepCommandOptimizeTest.java	Mon Nov 10 22:21:52 2008 +0900
@@ -1,8 +1,12 @@
 package test;
 
+import static org.junit.Assert.*;
+
 import java.util.LinkedList;
 import java.util.List;
 
+import org.junit.Test;
+
 import rep.REPCommand;
 import rep.REP;
 import rep.optimizers.NullOptimizer;
@@ -85,7 +89,15 @@
 		text.printAllText();
 	}
 	
+	
 	public static void main(String[] s){
+		RepCommandOptimizeTest t = new RepCommandOptimizeTest();
+		t.main0();
+	}
+
+	@Test
+	public void main0(){
+	
 		REPCommandOptimizer rco;
 
 		if (true)  rco = new DeleteInsertOptimizer();  //
@@ -107,7 +119,6 @@
 
 	}
 
-
 	private static void test(REPCommandOptimizer rco, List<REPCommand> cmdlist,
 			Text text1, Text text2) {
 		List<REPCommand> result;		// optimize
@@ -117,6 +128,7 @@
 		// this command list applied to other text, and print it.
 		text2.edit(result);
 		// check two texts.
+		assertEquals(text1.equals(text2),true);
 		if(!text1.equals(text2)){
 			System.out.println("two texts not match");
 			print(cmdlist, result, text1, text2);
--- a/test/Text.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/test/Text.java	Mon Nov 10 22:21:52 2008 +0900
@@ -7,36 +7,46 @@
 import rep.REPCommand;
 import rep.REP;
 
-public class Text {
+public class Text extends LinkedList<String> {
+
 
-	List<String> strList;
-
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	
 	public Text(String[] _strings){
-		strList = new LinkedList<String>(Arrays.asList(_strings));
+		super(Arrays.asList(_strings));
 	}
+	
 	public Text(List<String> _strings){
-		strList = new LinkedList<String>(_strings);
+		super(_strings);
 	}
 	
 	public String insert(int i, String str){
-		assert 0<=i && i<=strList.size();
-		strList.add(i, str);
+		assert 0<=i && i<=size();
+		add(i, str);
 		return null;
 	}
+	
 	public String delete(int i){
-		assert 0<=i && i<strList.size();
-		return strList.remove(i);
+		if (i>=size()) return "";
+		// assert 0<=i && i<size();
+		return remove(i);
 	}
+	
 	public String replace(int i, String str){
-		assert 0<=i && i<strList.size();
-		String replaced = strList.get(i);
-		strList.set(i, str);
+		//assert 0<=i && i<size();
+		String replaced ;
+		if (i<size()) {
+			replaced = get(i);
+		} else {
+			replaced = "";
+		}
+		set(i, str);
 		return replaced;
 	}
-	public String get(int i){
-		assert 0<=i && i<strList.size();
-		return strList.get(i);
-	}
+	
 	public String edit(REPCommand cmd){
 		if (cmd.cmd==REP.REPCMD_INSERT)        return insert(cmd.lineno, cmd.string);
 		//else if (cmd.cmd==REP.REPCMD_REPLACE)  return replace(cmd.lineno, cmd.string);
@@ -44,21 +54,16 @@
 		//else assert false;
 		return null;
 	}
+	
 	public void edit(List<REPCommand> cmdlist){
 		for (REPCommand cmd: cmdlist){
 			edit(cmd);
 		}
 	}
 
-	public int size(){
-		return strList.size();
-	}
 	public void printAllText(){
-		for( String str: strList){
+		for( String str: this){
 			System.out.println(str);
 		}
 	}
-	public boolean equals(Text _target){
-		return strList.equals(_target.strList);
-	}
 }
--- a/test/XMLTest.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/test/XMLTest.java	Mon Nov 10 22:21:52 2008 +0900
@@ -14,13 +14,13 @@
 	
 	public static void main(String[] args){
 		
-		Editor editor = new Editor(null,0, null);
+		Editor editor = new Editor(0,null,null);
 		editor.setEID(1);
 		editor.setHost("firefly.cr.ie.u-ryukyu.ac.jp");
 		//editor.setPort("56789");
 		editor.setName("Test.java");
 		
-		Editor editor2 = new Editor(null,1, null);
+		Editor editor2 = new Editor(1,null,null);
 		editor2.setEID(2);
 		editor2.setHost("teto.cr.ie.u-ryukyu.ac.jp");
 		//editor2.setPort("45678");
--- a/test/sematest/TestEditor.java	Mon Nov 10 22:19:34 2008 +0900
+++ b/test/sematest/TestEditor.java	Mon Nov 10 22:21:52 2008 +0900
@@ -39,6 +39,7 @@
 	private boolean inputLock=false;
 	public boolean detached=false;
 	public boolean master=false;
+	REPCommand quit=null;
 	private int syncCounter=0;
 	private boolean hasInputLock=false;
 	private int port;
@@ -62,7 +63,7 @@
 			cmds.add(new REPCommand(REP.SMCMD_PUT,0,0,0,0,name+"-file"));
 			cmds.add(new REPCommand(REP.REPCMD_INSERT,0,0,0,0,"m0"));
 			cmds.add(new REPCommand(REP.REPCMD_DELETE,0,0,0,0,"m0"));
-			cmds.add(new REPCommand(REP.SMCMD_QUIT,0,0,0,0,""));
+			//cmds.add(new REPCommand(REP.SMCMD_QUIT,0,0,0,0,""));
 		} else {
 			text = new Text(new String[0]);
 			cmds.add(new REPCommand(REP.SMCMD_JOIN,0,0,0,0,name));
@@ -182,7 +183,7 @@
 				 * clients simply disconnect from the session manager.
 				 */
 				cmds.clear();
-				sendCommand(cmd);
+				quit = cmd;
 				break;
 			case SMCMD_JOIN:
 			case SMCMD_PUT:
@@ -197,9 +198,14 @@
 				assert(false);
 			}
 		} else {
-			if(syncCounter==0)
+			if(syncCounter==0) {
 			// no more command to send, and we don't have syncCounter
 				timeout = 0;
+				if (quit!=null) {
+					sendCommand(quit);
+					quit=null;
+				}
+			}
 		}
 	}
 
@@ -229,9 +235,6 @@
 				addNop();
 			forwardCommand(cmd);
 			break;
-		case REPCMD_INSERT_ACK	:
-			assert(false);
-			break;
 		case REPCMD_DELETE	:
 			String del=""; 
 			if(cmd.lineno>text.size()) {
@@ -242,14 +245,12 @@
 			cmd.setString(del);
 			forwardCommand(cmd);
 			break;
-		 case REPCMD_DELETE_ACK	:
-				assert(false);
-			 break;
 		 case REPCMD_NOP		:
  			 if (cmd.eid!=REP.MERGE_EID.id)
  				 addNop();
 			 forwardCommand(cmd);
-			 break;		 case REPCMD_CLOSE	:
+			 break;		 
+		 case REPCMD_CLOSE	:
 		 case REPCMD_CLOSE_2	:
 				assert(false);
 			 break;
@@ -275,20 +276,15 @@
 			 // stop input processing after this command
 			 cmds.clear();
 			 break;
-		 case SMCMD_QUIT_ACK	:
-			 assert(false);
-			 break;
 		 case SMCMD_START_MERGE :
 			 // lock user input during merge (optional)
 			 inputLock = hasInputLock;
 			 cmd.cmd = REP.SMCMD_START_MERGE_ACK;
 			 sendCommand(cmd);
 			 break;
-		 case SMCMD_START_MERGE_ACK :
-			 assert(false);
-			 break;
 		 case SMCMD_END_MERGE :
 			 inputLock = false;
+			 prevSeq = seq;
 			 break;
 		 case SMCMD_QUIT_2 :
 			 if (cmd.eid!=eid) {
@@ -318,8 +314,8 @@
 	private void addNop() {
 		if (seq!=prevSeq) return;
 		// We haven't send any command, add nop before retransmition.
+		prevSeq = seq;
 		sendCommand(nop);
-		prevSeq = seq;
 	}
 
 	public int getPort() {