diff test/editortest/REPEditor.java @ 417:267f9748e826

(no commit message)
author one
date Wed, 31 Dec 2008 14:52:45 +0900
parents
children 7ff127c8ad64
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/REPEditor.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,247 @@
+package test.editortest;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.SelectionKey;
+import java.util.LinkedList;
+import rep.REP;
+import rep.REPCommand;
+import rep.REPCommandPacker;
+import rep.channel.REPSelectionKey;
+import rep.channel.REPSelector;
+import rep.channel.REPSocketChannel;
+
+
+public class REPEditor extends Thread implements REPTextListener{
+	
+	private REPSocketChannel<REPCommand> channel;
+	REPSelector<REPCommand> selector;
+	private boolean running = true;
+	private boolean inputLock = false;
+	private long timeout = 1;
+	private int syncCounter = 0;
+	private LinkedList<REPCommand> userCommand = new LinkedList<REPCommand>();
+	private LinkedList<Runnable> runners = new LinkedList<Runnable>();
+	private String name = "test";
+	private int seq;
+	private int eid;
+	private int sid;
+	private REPText repText;
+	private boolean hasInputLock;
+	private boolean master;
+	private boolean syncEnable = true;
+	private LogTarget logTarget;
+	
+	public REPEditor(REPText repText, boolean master){
+		this.repText = repText;
+		this.master = master;
+		repText.addTextListener(this);
+		if(master){
+			userCommand.add(new REPCommand(REP.SMCMD_PUT,0,0,0,0,name +"-file"));
+		}else{
+			userCommand.add(new REPCommand(REP.SMCMD_JOIN, 0, 0, 0, 0, name));
+		}
+	}
+
+	public void textDeleted(REPTextEvent event) {
+		Logger.print(event.getText());
+		addUserInput(new REPCommand(REP.REPCMD_DELETE_USER, 0, 0, 0, event.getLineno(), event.getText()));
+	}
+
+	public void textInserted(REPTextEvent event) {
+		Logger.print(event.getText());
+		addUserInput(new REPCommand(REP.REPCMD_INSERT_USER, 0, 0, 0, event.getLineno(), event.getText()));
+	}
+
+	private void addUserInput(final REPCommand command) {
+		Runnable runner = new Runnable(){
+			public void run(){
+				userCommand.add(command);
+				timeout = 1;
+			}
+		};
+		synchronized(runners){
+			runners.add(runner);
+		}
+		if(selector != null){
+			selector.wakeup();
+		}
+	}
+	
+	public void run(){
+		/*
+		 * Create Socket and connect to the session manager
+		 */
+		try {
+			channel = REPSocketChannel.<REPCommand>create(new REPCommandPacker());
+		} catch (IOException e) {
+			e.printStackTrace();
+			return;
+		}
+		try {
+			InetSocketAddress semaIP = new InetSocketAddress("localhost", 8766);
+			while (!channel.connect(semaIP)){
+				Logger.print("SeMa not listen to socket yet, wait");
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+			return;
+		}
+		/*
+		 * Start editor main loop
+		 *         public REPCommand(REP cmd,int sid,int eid, int seq, int lineno,  String string) 
+		 */
+		try {
+			mainloop();
+		} catch (IOException e) {
+		}
+	}
+
+	/*
+	 * Editor main loop with input lock
+	 */
+	private void mainloop() throws IOException {
+		
+		channel.configureBlocking(false);
+		selector = REPSelector.create();
+		channel.register(selector, SelectionKey.OP_READ);
+		while(running) {
+			
+			synchronized(runners){
+				for(Runnable runner : runners){
+					runner.run();
+				}
+				runners.clear();
+			}
+			
+			if (inputLock) {
+				// No user input during merge mode (optional)
+				if (selector.select(0)>0) {
+					handle(channel.read());
+				}
+				continue;
+			} else if (selector.select(timeout)<=0) {
+				if (syncCounter>0) {
+					syncText(); // send the master editor buffer to clients. 
+				}
+				userInput();
+			}
+			// selector(timeout) returns 0, but it may contain readable channel..
+			for(REPSelectionKey<REPCommand> key : selector.selectedKeys1()) {
+				REPSocketChannel<REPCommand> ch = key.channel1();
+				handle(ch.read());
+			}
+		}
+	}
+
+	private void handle(REPCommand command) {
+		Logger.print(logTarget, command);
+		if(command == null) return;
+		switch(command.cmd){
+		case REPCMD_DELETE:
+			if(command.eid != eid){
+				String del = repText.delete(command.lineno);
+				command.setString(del);
+			}
+			forward(command);
+			break;
+		case REPCMD_INSERT:
+			if(command.eid != eid){
+				repText.insert(command.lineno, command.string);
+			}
+			forward(command);
+			break;
+		case REPCMD_NOP:
+		case REPCMD_INSERT_ACK:
+		case REPCMD_DELETE_ACK:
+			forward(command);
+			break;	
+		case SMCMD_PUT_ACK:
+			sid = command.sid;
+			eid = command.eid;
+			name += "(eid="+eid+",sid="+sid+")";
+			inputLock = false;
+			break;
+		case SMCMD_JOIN_ACK	:
+			sid = command.sid;
+			eid = command.eid;
+			name += "(eid="+eid+",sid="+sid+")";
+			inputLock = false;
+			break;
+		case SMCMD_START_MERGE :
+			// lock user input during merge (optional)
+			inputLock = hasInputLock;
+			command.cmd = REP.SMCMD_START_MERGE_ACK;
+			send(command);
+			break;
+		case SMCMD_END_MERGE :
+			inputLock = false;
+			break;
+		case SMCMD_SYNC:
+			// start contents sync with newly joined editor
+			command.cmd = REP.SMCMD_SYNC_ACK;
+			forward(command);
+			//if (cmd.eid==eid) {
+			if (master && syncEnable ) {
+				syncCounter = 1;
+				timeout = 1;
+			}
+			break;
+		}
+	}
+
+	private void userInput() {
+		Logger.print();
+		REPCommand command = userCommand.poll();
+		if(command != null){
+			switch(command.cmd){
+			case REPCMD_DELETE_USER:
+				send(command);
+				break;
+			case REPCMD_INSERT_USER:
+				send(command);
+				break;
+			case SMCMD_PUT:
+			case SMCMD_JOIN:
+				send(command);
+				break;
+			}
+		}else{
+			if(syncCounter == 0){
+				timeout = 0;
+			}
+		}
+	}
+
+	private void forward(REPCommand command) {
+		REPCommand cmd = new REPCommand(command);
+		channel.write(cmd);
+	}
+
+	private void send(REPCommand command) {
+		REPCommand cmd = new REPCommand(command);
+		cmd.setSEQID(seq++);
+		cmd.setEID(eid);
+		cmd.setSID(sid);
+		channel.write(cmd);
+	}
+
+	private void syncText() {
+		if(syncCounter>repText.size()){
+			syncCounter = 0;
+		}else {
+			if(inputLock) return;
+			int i = syncCounter - 1;
+			REPCommand del = new REPCommand(REP.REPCMD_DELETE_USER, sid, eid, 0, i, repText.get(i));
+			REPCommand ins = new REPCommand(REP.REPCMD_INSERT_USER, sid, eid, 0, i, repText.get(i));
+			send(del);
+			send(ins);
+			syncCounter++;
+		}
+	}
+	
+	public void setLogTarget(LogTarget target){
+		logTarget = target;
+	}
+
+}