# HG changeset patch # User one # Date 1230702765 -32400 # Node ID 267f9748e8262539d8182ddad1c8b25c89457e56 # Parent b7f42fc75a367080912e35361e11388d7f9d5ab3 (no commit message) diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/REPCommandReceiver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/editortest/REPCommandReceiver.java Wed Dec 31 14:52:45 2008 +0900 @@ -0,0 +1,71 @@ +package test.editortest; + +import java.io.IOException; +import java.nio.channels.SelectionKey; + +import rep.REPCommand; +import rep.channel.REPSelectionKey; +import rep.channel.REPSelector; +import rep.channel.REPSocketChannel; + +public class REPCommandReceiver extends Thread{ + + REPSocketChannel channel; + boolean running = true; + private boolean inputLock=false; + long timeout = 1; + private int syncCounter=0; + + public REPCommandReceiver(REPSocketChannel channel, REPSelector selector){ + this.channel = channel; + } + + public void run(){ + try { + mainloop(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void mainloop() throws IOException { + + channel.configureBlocking(false); + REPSelector selector = REPSelector.create(); + channel.register(selector, SelectionKey.OP_READ); + while(running) { + 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 key : selector.selectedKeys1()) { + REPSocketChannel ch = key.channel1(); + handle(ch.read()); + } + } + } + + private void userInput() { + // TODO Auto-generated method stub + + } + + private void syncText() { + // TODO Auto-generated method stub + + } + + private void handle(REPCommand read) { + // TODO Auto-generated method stub + + } +} diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/REPEditor.java --- /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 channel; + REPSelector selector; + private boolean running = true; + private boolean inputLock = false; + private long timeout = 1; + private int syncCounter = 0; + private LinkedList userCommand = new LinkedList(); + private LinkedList runners = new LinkedList(); + 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.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 key : selector.selectedKeys1()) { + REPSocketChannel 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; + } + +} diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/REPTextEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/editortest/REPTextEvent.java Wed Dec 31 14:52:45 2008 +0900 @@ -0,0 +1,20 @@ +package test.editortest; + +public class REPTextEvent { + + private int lineno; + private String text; + + public REPTextEvent(int lineno, String text) { + this.lineno = lineno; + this.text = text; + } + + public int getLineno(){ + return lineno; + } + + public String getText(){ + return text; + } +} diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/REPTextListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/editortest/REPTextListener.java Wed Dec 31 14:52:45 2008 +0900 @@ -0,0 +1,9 @@ +package test.editortest; + +public interface REPTextListener { + + public void textInserted(REPTextEvent event); + + public void textDeleted(REPTextEvent event); + +} diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/REPTextWithJTextArea.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/editortest/REPTextWithJTextArea.java Wed Dec 31 14:52:45 2008 +0900 @@ -0,0 +1,156 @@ +package test.editortest; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; + +public class REPTextWithJTextArea implements REPText, DocumentListener, ActionListener { + + private JTextArea textArea; + private String BR = System.getProperty("line.separator"); + private LinkedList textListenerList = new LinkedList(); + private JTextField lineField; + private JTextField textField; + private JButton deleteButton; + private JButton insertButton; + + public REPTextWithJTextArea(JTextArea textArea, JTextField lineField, JTextField textField, JButton deleteButton, JButton insertButton) { + this.textArea = textArea; + this.lineField = lineField; + this.textField = textField; + this.deleteButton = deleteButton; + this.insertButton = insertButton; + textArea.getDocument().addDocumentListener(this); + textField.addActionListener(this); + deleteButton.addActionListener(this); + insertButton.addActionListener(this); + } + + public String delete(int lineno) { + for(int i = size(); i <= lineno; i++){ + increaseLine(); + } + + String del = getLineText(lineno); + try { + int start = textArea.getLineStartOffset(lineno); + int end = textArea.getLineEndOffset(lineno); + textArea.replaceRange("", start, end); + } catch (BadLocationException e) { + e.printStackTrace(); + } + return del; + } + + public void insert(int lineno, String text) { + for(int i = size(); i <= lineno; i++){ + increaseLine(); + } + + String text2 = text + BR; + try { + int offset = textArea.getLineStartOffset(lineno); + textArea.insert(text2, offset); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + + private void increaseLine(){ + textArea.append(BR); + } + + private String getLineText(int lineno){ + String text = null; + try { + int start = textArea.getLineStartOffset(lineno); + int end = textArea.getLineEndOffset(lineno); + text = textArea.getText(start, end-start); + String text2 = text.replace(BR, ""); + text = text2; + } catch (BadLocationException e) { + e.printStackTrace(); + } + return text; + } + + public int size() { + return textArea.getLineCount(); + } + + public String get(int i) { + return getLineText(i); + } + + public List list() { + LinkedList list = new LinkedList(); + for(int i = 0; i < size(); i++){ + list.add(getLineText(i)); + } + return list; + } + + public void addTextListener(REPTextListener listener) { + textListenerList.add(listener); + } + + public void changedUpdate(DocumentEvent e) { + Logger.print(e); + } + + public void insertUpdate(DocumentEvent e) { + Logger.print(e); + + } + + public void removeUpdate(DocumentEvent e) { + Logger.print(e); + } + + public void actionPerformed(ActionEvent e) { + if(e.getSource() == textField){ + userInsert(); + textField.setText(""); + }else if(e.getSource() == deleteButton){ + userDelete(); + }else if(e.getSource() == insertButton){ + userInsert(); + } + } + + private void userDelete() { + int lineno = 0; + try { + lineno = Integer.parseInt((lineField.getText())); + if(lineno < 0) lineno = 0; + }catch(NumberFormatException e){} + + String del = delete(lineno); + for(REPTextListener listener : textListenerList){ + listener.textDeleted(new REPTextEvent(lineno, del)); + } + } + + private void userInsert() { + int lineno; + try { + lineno = Integer.parseInt((lineField.getText())); + }catch(NumberFormatException e){ + lineno = 0; + } + String text = textField.getText(); + insert(lineno, text); + for(REPTextListener listener : textListenerList){ + listener.textInserted(new REPTextEvent(lineno, text)); + } + } + +} diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/SimpleEditorForREPEditor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/editortest/SimpleEditorForREPEditor.java Wed Dec 31 14:52:45 2008 +0900 @@ -0,0 +1,129 @@ +package test.editortest; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.JToolBar; + +public class SimpleEditorForREPEditor extends JFrame implements ActionListener, LogTarget{ + + /** + * + */ + private static final long serialVersionUID = 1L; + private JButton putButton; + private JButton joinButton; + private JTextField lineField; + private JTextField textField; + private JTextArea textArea; + private JScrollPane scrollPane1; + private JTextArea console; + private JScrollPane scrollPane2; + private JSplitPane splitPane; + private String BR = System.getProperty("line.separator"); + private JButton deleteButton; + private JButton insertButton; + + public SimpleEditorForREPEditor(String title){ + super(title); + setSize(new Dimension(640, 480)); + setLayout(new BorderLayout()); + + setToolBar(); + setEditor(); + setConsole(); + setSplitPane(); + } + + private void setToolBar() { + JToolBar toolbar = new JToolBar(); + putButton = new JButton("put"); + joinButton = new JButton("join"); + putButton.addActionListener(this); + joinButton.addActionListener(this); + + JLabel label1 = new JLabel("line"); + JLabel label2 = new JLabel("text"); + lineField = new JTextField(); + textField = new JTextField(); + + deleteButton = new JButton("delete"); + insertButton = new JButton("insert"); + + toolbar.add(putButton); + toolbar.add(joinButton); + toolbar.addSeparator(); + toolbar.add(label1); + toolbar.add(lineField); + toolbar.add(label2); + toolbar.add(textField); + toolbar.addSeparator(); + toolbar.add(deleteButton); + toolbar.add(insertButton); + + add(toolbar, BorderLayout.NORTH); + } + + private void setEditor(){ + textArea = new JTextArea(); + textArea.setEditable(false); + textArea.setFont(new Font("Monaco", Font.PLAIN, textArea.getFont().getSize())); + + scrollPane1 = new JScrollPane(textArea); + } + + private void setConsole(){ + console = new JTextArea(); + console.setFont(new Font("Monaco", Font.PLAIN, console.getFont().getSize()-2)); + console.setEditable(false); + scrollPane2 = new JScrollPane(console); + } + + private void setSplitPane(){ + splitPane = new JSplitPane(); + splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane.add(scrollPane1, JSplitPane.TOP); + splitPane.add(scrollPane2, JSplitPane.BOTTOM); + splitPane.setDividerLocation(300); + add(splitPane, BorderLayout.CENTER); + } + + public void actionPerformed(ActionEvent e) { + if(e.getSource() == putButton){ + repPut(); + }else if(e.getSource() == joinButton){ + repJoin(); + } + } + + private void repPut() { + REPEditor repEditor = new REPEditor(new REPTextWithJTextArea(textArea, lineField, textField, deleteButton, insertButton), true); + repEditor.start(); + repEditor.setLogTarget(this); + putButton.setEnabled(false); + joinButton.setEnabled(false); + } + + private void repJoin() { + REPEditor repEditor = new REPEditor(new REPTextWithJTextArea(textArea, lineField, textField, deleteButton, insertButton), false); + repEditor.start(); + repEditor.setLogTarget(this); + putButton.setEnabled(false); + joinButton.setEnabled(false); + } + + public void printLog(String msg) { + console.append(msg + BR); + } + +} diff -r b7f42fc75a36 -r 267f9748e826 test/editortest/TestSimpleEditor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/editortest/TestSimpleEditor.java Wed Dec 31 14:52:45 2008 +0900 @@ -0,0 +1,41 @@ +package test.editortest; + +import java.io.IOException; + +import test.AutoSelectManager; + +public class TestSimpleEditor { + + /** + * @param args + * @throws IOException + * @throws InterruptedException + */ + public static void main(final String[] args) throws InterruptedException, IOException { + + Runnable runnable = new Runnable(){ + public void run(){ + try { + AutoSelectManager.main(args); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }; + + Thread thread = new Thread(runnable); + thread.start(); + + SimpleEditorForREPEditor editor1 = new SimpleEditorForREPEditor("test1"); + editor1.setVisible(true); + + SimpleEditorForREPEditor editor2 = new SimpleEditorForREPEditor("test2"); + editor2.setVisible(true); + + SimpleEditorForREPEditor editor3 = new SimpleEditorForREPEditor("test3"); + editor3.setVisible(true); + } + +}