changeset 2:3c188a5b69ef

add network bbs
author tatsuki
date Mon, 27 Jun 2016 05:06:19 +0900
parents 64a72a7a0491
children f3d30646c863
files src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/BoardRenewTime.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/BulletinBoardJungleManager.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/DistributeApp.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/NetworkBulletinBoard.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/NetworkJungleBulletinBoard.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/RequestNumCheckServlet.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/ShowMessageWithTimeStampServlet.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/codesegment/LogPutCodeSegment.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/codesegment/LogUpdateCodeSegment.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/codesegment/StartBBSCodeSegment.java src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/io/NullOutputStream.java
diffstat 11 files changed, 1129 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/BoardRenewTime.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,8 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+public interface BoardRenewTime {
+
+	public String getboardName();
+	public Long getRenewTime();	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/BulletinBoardJungleManager.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,109 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+
+import jp.ac.u_ryukyu.ie.cr.jungle.DefaultJungle;
+import jp.ac.u_ryukyu.ie.cr.jungle.Jungle;
+import jp.ac.u_ryukyu.ie.cr.jungle.JungleTree;
+import jp.ac.u_ryukyu.ie.cr.jungle.JungleTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.DefaultNodePath;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.DefaultTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.TreeNode;
+import jp.ac.u_ryukyu.ie.cr.jungle.traverser.DefaultTraverser;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.Either;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.Error;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.operations.NetworkTreeOperationLog;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.transaction.JungleUpdater;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class BulletinBoardJungleManager {
+	private static BulletinBoardJungleManager instance = new BulletinBoardJungleManager();
+	private Jungle jungle;
+	private static AtomicInteger requestCounter = new AtomicInteger(0);
+
+	private BulletinBoardJungleManager() {
+		jungle = new DefaultJungle(null,"default",new DefaultTreeEditor(new DefaultTraverser()));
+	}
+	
+	public static int requestGetAndIncrement() {
+		return requestCounter.getAndIncrement();
+	}
+	
+	public static int requestIncrementAndGet() {
+		return requestCounter.incrementAndGet();
+	}
+	
+	public static BulletinBoardJungleManager getInstantce() {
+		return instance;
+	}
+	
+	public static void setJungle(Jungle _j) {
+		instance.jungle = _j;
+	}
+	public static AtomicInteger getRequestCounter() {
+		return requestCounter;
+	}
+	
+	public static Jungle getJungle() {
+		return instance.jungle;
+	}
+	
+	public static JungleTree createNewTree(String name) {
+		return instance.jungle.createNewTree(name);	
+	}
+
+	public static Either<Error, JungleTreeEditor> update(NetworkTreeOperationLog netLog) {
+		String treeName = netLog.getTreeName();
+		Jungle jungle = jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.BulletinBoardJungleManager.getJungle();
+		if (jungle.getTreeByName(treeName) == null) {
+			if(null == jungle.createNewTree(treeName)){
+				throw new IllegalStateException();
+			}
+		}
+		Either<Error, JungleTreeEditor> either = null;
+		JungleTree tree = jungle.getTreeByName(treeName);
+		
+		long timestamp = System.currentTimeMillis();
+		ByteBuffer tBuffer = ByteBuffer.allocate(16);
+		DefaultNodePath root = new DefaultNodePath();
+		tBuffer.putLong(timestamp);
+		do {
+			JungleTreeEditor editor = tree.getLocalTreeEditor();
+			/* 
+			 * Merge. 
+			 */
+			int pos = calculatePosition(tree.getRootNode(), netLog.getTimeStamp());
+			either = JungleUpdater.edit(editor, netLog, pos);
+			if(either.isA()) {
+				throw new IllegalStateException();
+			}
+			editor = either.b();
+			either = editor.putAttribute(root, "renewtime", tBuffer);
+			if(either.isA()) {
+				throw new IllegalStateException();
+			}
+			editor = either.b();
+			either = editor.success();
+		}while(either.isA());
+		requestIncrementAndGet();
+		return either;
+	}
+	
+	private static int calculatePosition(TreeNode node, long newNodeTimeStamp) {
+		int count = 0;
+		long childTimeStamp = 0;
+		for(TreeNode n : node.getChildren()) {
+			ByteBuffer timestamp = n.getAttributes().get("timestamp");
+			if(timestamp == null) {
+				return count;
+			}
+			childTimeStamp = timestamp.getLong(0);
+			if (newNodeTimeStamp < childTimeStamp) {
+				break;
+			}
+			count++;
+		}
+		return count;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/DistributeApp.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,20 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+import alice.topology.node.TopologyNode;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.codesegment.StartBBSCodeSegment;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.remote.RemoteConfig;
+
+public class DistributeApp {
+    public static void main(String[] args) throws Exception {
+        RemoteConfig conf = new RemoteConfig(args);
+        System.out.println("test");
+        if (conf.getManagerHostName() == null) {
+            // String localHostName ="localhost";
+            // HostMessage host = new HostMessage(localHostName, conf.localPort);
+            StartBBSCodeSegment cs1 = new StartBBSCodeSegment(args, conf.bbsPort);
+            cs1.ods.put("host", "node0");
+        } else {
+            new TopologyNode(conf, new StartBBSCodeSegment(args, conf.bbsPort));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/NetworkBulletinBoard.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,16 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+
+import jp.ac.u_ryukyu.ie.cr.jungle.bbs.BulletinBoard;
+
+public interface NetworkBulletinBoard extends BulletinBoard {
+	public void init();
+	public int getRequestNum();
+	public long getRenewTime(String boardName);
+	public void createFolder(String boardName, String author, String msg, String key, String _nodeNum);
+	public void createAttribute(String boardName, String uuid, String author, String msg, String key);
+	public void editAttribute(String boardName, String path, String id, String message);
+	public void deleteAttribute(String _board, String _path, String id);
+	public void deleteNode(String _board, String _path, String id);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/NetworkJungleBulletinBoard.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,691 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+
+import jp.ac.u_ryukyu.ie.cr.jungle.Jungle;
+import jp.ac.u_ryukyu.ie.cr.jungle.JungleTree;
+import jp.ac.u_ryukyu.ie.cr.jungle.JungleTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.jungle.bbs.BoardMessage;
+import jp.ac.u_ryukyu.ie.cr.jungle.bbs.GetAttributeImp;
+import jp.ac.u_ryukyu.ie.cr.jungle.bbs.IterableConverter;
+import jp.ac.u_ryukyu.ie.cr.jungle.core.Children;
+import jp.ac.u_ryukyu.ie.cr.jungle.persistent.ChangeList;
+import jp.ac.u_ryukyu.ie.cr.jungle.persistent.ChangeListReader;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.DefaultNodePath;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.DefaultTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.TreeNode;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.logger.DefaultOperationLog;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.logger.LoggingNode;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.impl.logger.OperationLog;
+import jp.ac.u_ryukyu.ie.cr.jungle.store.trasnformer.NodeEditor;
+import jp.ac.u_ryukyu.ie.cr.jungle.traverser.DefaultEvaluator;
+import jp.ac.u_ryukyu.ie.cr.jungle.traverser.DefaultTraverser;
+import jp.ac.u_ryukyu.ie.cr.jungle.traverser.Traversal;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.DefaultEither;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.Either;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.Error;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.BulletinBoardJungleManager;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.NetworkBulletinBoard;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.core.NetworkDefaultJungle;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.persistent.AliceJournal;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.persistent.NetworkJournal;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.persistent.PersistentJournal;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.transaction.JungleUpdater;
+import junit.framework.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class NetworkJungleBulletinBoard implements NetworkBulletinBoard {
+    protected final Jungle jungle;
+    private final NetworkJournal journal;
+    private final String LOG_DIR;
+    private Boolean persistentFlag;
+    private AtomicInteger requestCounter;
+    private long renewTime;
+
+    private NetworkJungleBulletinBoard(String _uuid, NetworkJournal _journal) {
+        journal = _journal;
+        jungle = new NetworkDefaultJungle(journal, _uuid, new DefaultTreeEditor(new DefaultTraverser()));
+        BulletinBoardJungleManager.setJungle(jungle);
+        persistentFlag = false;
+        requestCounter = BulletinBoardJungleManager.getRequestCounter();
+        LOG_DIR = "./log";
+        renewTime = 0;
+    }
+
+    public NetworkJungleBulletinBoard(String _uuid) {
+        this(_uuid, new AliceJournal());
+        jungle.createNewTree("boards");
+    }
+
+    public static NetworkBulletinBoard NewPersistentJungle(String _uuid) {
+        NetworkJungleBulletinBoard board = new NetworkJungleBulletinBoard(_uuid, new PersistentJournal());
+        board.persistentFlag = true;
+        return board;
+    }
+
+    public void init() {
+        if (!persistentFlag) {
+            return;
+        }
+        checkAndCreateLogDirectory();
+        try {
+            commitLogRecover();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void checkAndCreateLogDirectory() {
+        File logFile = new File(LOG_DIR);
+        if (!logFile.exists()) {
+            logFile.mkdir();
+            return;
+        }
+        if (logFile.isFile()) {
+            logFile.delete();
+            logFile.mkdir();
+        }
+    }
+
+    public void commitLogRecover() throws IOException {
+        File[] logFiles = new File(LOG_DIR).listFiles();
+        for (File logFile : logFiles) {
+            commitLogRecover(logFile);
+            logFile.delete();
+        }
+        if (jungle.getTreeByName("boards") == null) {
+            jungle.createNewTree("boards");
+        }
+    }
+
+    private void commitLogRecover(File logFile) throws IOException {
+        journal.setInputFile(logFile);
+        ChangeListReader reader = journal.getReader();
+        if (reader == null)
+            return;
+        for (ChangeList chList : reader) {
+            String treeName = chList.getTreeName();
+            JungleTree tree = jungle.getTreeByName(treeName);
+            if (tree == null) {
+                tree = jungle.createNewTree(treeName);
+            }
+            JungleTreeEditor editor = tree.getLocalTreeEditor();
+            Either<Error, JungleTreeEditor> either = JungleUpdater.edit(editor, chList);
+            editor = either.b();
+            if (either.isA()) {
+                throw new IOException("Failed commit log recovery");
+            }
+            editor.success();
+        }
+    }
+
+    public Iterable<String> getBoards() {
+        JungleTree tree = jungle.getTreeByName("boards");
+        TreeNode node = tree.getRootNode();
+        Children chs = node.getChildren();
+
+        IterableConverter.Converter<String, TreeNode> converter = new IterableConverter.Converter<String, TreeNode>() {
+            public String conv(TreeNode _b) {
+                ByteBuffer e = _b.getAttributes().get("name");
+                System.out.println(new String(e.array()));
+                return new String(e.array());
+            }
+        };
+
+        return new IterableConverter<String, TreeNode>(chs, converter);
+    }
+
+    public long getRenewTime(String _boardName) {
+        return renewTime;
+    }
+
+    public void createBoards(final String _name, final String _author, final String _initMessage, final String _editKey) {
+        requestCounter.incrementAndGet();
+        if (null == jungle.createNewTree(_name)) {
+            throw new IllegalStateException();
+        }
+
+        JungleTree tree = jungle.getTreeByName("boards");
+        JungleTreeEditor editor = tree.getTreeEditor();
+        DefaultNodePath root = new DefaultNodePath();
+        Either<Error, JungleTreeEditor> either = editor.addNewChildAt(root, 0);
+        if (either.isA()) {
+            throw new IllegalStateException();
+        }
+        editor = either.b();
+
+        either = editor.putAttribute(root.add(0), "name", ByteBuffer.wrap(_name.getBytes()));
+        if (either.isA()) {
+            throw new IllegalStateException();
+        }
+        editor = either.b();
+        final long timestamp = System.currentTimeMillis();
+        ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        either = editor.putAttribute(root.add(0), "timestamp", tBuffer);
+        if (either.isA()) {
+            throw new IllegalStateException();
+        }
+        either = either.b().success();
+        if (either.isA()) {
+            throw new IllegalStateException();
+        }
+
+        tree = jungle.getTreeByName(_name);
+        editor = tree.getTreeEditor();
+        either = editor.addNewChildAt(root, 0);
+        if (either.isA()) {
+            throw new IllegalStateException();
+        }
+        editor = either.b();
+
+        NodeEditor e = new NodeEditor() {
+            ByteBuffer tBuffer2 = ByteBuffer.allocate(16);
+
+            public Either<Error, LoggingNode> edit(TreeNode node) {
+                LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                logNode = logNode.getAttributes().put("author", ByteBuffer.wrap(_author.getBytes())).b();
+                logNode = logNode.getAttributes().put("mes", ByteBuffer.wrap(_initMessage.getBytes())).b();
+                logNode = logNode.getAttributes().put("key", ByteBuffer.wrap(_editKey.getBytes())).b();
+                tBuffer2.putLong(timestamp);
+                logNode = logNode.getAttributes().put("timestamp", tBuffer2).b();
+                return DefaultEither.newB(logNode);
+            }
+
+            @Override
+            public LoggingNode wrap(TreeNode node, OperationLog op) {
+                return new LoggingNode(node, op);
+            }
+        };
+
+        either = editor.edit(root.add(0), e);
+        if (either.isA()) {
+            throw new IllegalStateException();
+        }
+        either.b().success();
+
+    }
+
+    public void createFolder(final String _board, final String _author, final String _message, final String _editKey,
+                             String _path) {
+        JungleTree tree = jungle.getTreeByName(_board);
+        if (tree == null) {
+            throw new IllegalStateException();
+        }
+
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+
+        requestCounter.incrementAndGet();
+        Either<Error, JungleTreeEditor> either;
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+
+        do {
+            TreeNode node = tree.getRootNode();
+            DefaultTraverser traverser = new DefaultTraverser();
+            DefaultEvaluator evaluator = new DefaultEvaluator(path);
+            Either<Error, Traversal> ret = traverser.traverse(node, evaluator);
+            if (ret.isA()) {
+                Assert.fail();
+            }
+
+            Traversal traversal = ret.b();
+            TreeNode target = traversal.destination();
+            int size = target.getChildren().size();
+            JungleTreeEditor editor = tree.getTreeEditor();
+            either = editor.addNewChildAt(path, size);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+
+            NodeEditor e = new NodeEditor() {
+
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    logNode = logNode.getAttributes().put("mes", ByteBuffer.wrap(_message.getBytes())).b();
+                    logNode = logNode.getAttributes().put("timestamp", tBuffer).b();
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+
+            };
+            path = path.add(size);
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+
+    }
+
+    public void createBoardMessage(final String _board, final String _author, final String _message, final String _editKey) {
+        requestCounter.incrementAndGet();
+        JungleTree tree = jungle.getTreeByName(_board);
+        if (tree == null) {
+            throw new IllegalStateException();
+        }
+
+        Either<Error, JungleTreeEditor> either;
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        do {
+
+            TreeNode node = tree.getRootNode();
+            int size = node.getChildren().size();
+            DefaultNodePath path = new DefaultNodePath();
+
+            JungleTreeEditor editor = tree.getTreeEditor();
+            either = editor.addNewChildAt(path, size);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+
+            NodeEditor e = new NodeEditor() {
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    logNode = logNode.getAttributes().put("author", ByteBuffer.wrap(_author.getBytes())).b();
+                    logNode = logNode.getAttributes().put("mes", ByteBuffer.wrap(_message.getBytes())).b();
+                    logNode = logNode.getAttributes().put("key", ByteBuffer.wrap(_editKey.getBytes())).b();
+                    logNode = logNode.getAttributes().put("timestamp", tBuffer).b();
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+            };
+            path = path.add(size);
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+
+    }
+
+    public void editMessage(String _board, String _path, final String _author, final String _message,
+                            final String _editKey) {
+        requestCounter.incrementAndGet();
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        JungleTree tree = jungle.getTreeByName(_board);
+        Either<Error, JungleTreeEditor> either = null;
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+        do {
+
+            JungleTreeEditor editor = tree.getTreeEditor();
+            NodeEditor e = new NodeEditor() {
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    System.out.println(new String(node.getAttributes().get("mes").array()));
+                    logNode = logNode.getAttributes().put("author", ByteBuffer.wrap(_author.getBytes())).b();
+                    logNode = logNode.getAttributes().put("mes", ByteBuffer.wrap(_message.getBytes())).b();
+                    logNode = logNode.getAttributes().put("key", ByteBuffer.wrap(_editKey.getBytes())).b();
+                    logNode = logNode.getAttributes().put("timestamp", tBuffer).b();
+                    System.out.println(new String(node.getAttributes().get("mes").array()));
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+            };
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+        renewTime = timestamp;
+    }
+
+    public void createAttribute(String _board, String _path, final String _author, final String _message,
+                                final String _editKey) {
+        requestCounter.incrementAndGet();
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        JungleTree tree = jungle.getTreeByName(_board);
+        Either<Error, JungleTreeEditor> either = null;
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+
+        do {
+            JungleTreeEditor editor = tree.getTreeEditor();
+            NodeEditor e = new NodeEditor() {
+                String str;
+
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    str = "0";
+                    int count = 0;
+                    for (; logNode.getAttributes().get("mes" + String.valueOf(count)) != null; count++) {
+                    }
+                    str = String.valueOf(count);
+                    logNode = logNode.getAttributes().put("mes" + str, ByteBuffer.wrap(_message.getBytes())).b();
+                    logNode = logNode.getAttributes().put("timestamp" + str, tBuffer).b();
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+            };
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+    }
+
+    public void editAttribute(String _bname, String _path, final String id, final String _message) {
+        requestCounter.incrementAndGet();
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        JungleTree tree = jungle.getTreeByName(_bname);
+        Either<Error, JungleTreeEditor> either = null;
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+
+        do {
+            JungleTreeEditor editor = tree.getTreeEditor();
+            NodeEditor e = new NodeEditor() {
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    logNode = logNode.getAttributes().put("mes" + id, ByteBuffer.wrap(_message.getBytes())).b();
+                    logNode = logNode.getAttributes().put("timestamp" + id, tBuffer).b();
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+            };
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+    }
+
+    public void deleteNode(String _board, String _path, String _id) {
+        requestCounter.incrementAndGet();
+        int id = Integer.parseInt(_id);
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        JungleTree tree = jungle.getTreeByName(_board);
+        Either<Error, JungleTreeEditor> either = null;
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+
+        do {
+            JungleTreeEditor editor = tree.getTreeEditor();
+
+            either = editor.deleteChildAt(path, id);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+
+    }
+
+    public void deleteAttribute(String _board, String _path, final String id) {
+        requestCounter.incrementAndGet();
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        JungleTree tree = jungle.getTreeByName(_board);
+        Either<Error, JungleTreeEditor> either = null;
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+
+        do {
+            JungleTreeEditor editor = tree.getTreeEditor();
+            NodeEditor e = new NodeEditor() {
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    logNode = logNode.getAttributes().delete("mes" + id).b();
+                    logNode = logNode.getAttributes().delete("timestamp" + id).b();
+                    int count = Integer.parseInt(id);
+                    for (; logNode.getAttributes().get("mes" + String.valueOf(count + 1)) != null; ) {
+                        logNode = logNode.getAttributes()
+                                .put("mes" + count, node.getAttributes().get("mes" + String.valueOf(count + 1))).b();
+                        logNode = logNode.getAttributes().put("timestamp" + count, tBuffer).b();
+                        count++;
+                    }
+                    if (count != Integer.parseInt(id)) {
+                        logNode = logNode.getAttributes().delete("timestamp" + count).b();
+                        logNode = logNode.getAttributes().delete("mes" + count).b();
+                    }
+
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+            };
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+    }
+
+    public void editMatrixMessage(String _board, String _uuid, final String _author, final String _message,
+                                  final String _editKey) {
+        requestCounter.incrementAndGet();
+        final long timestamp = System.currentTimeMillis();
+        final ByteBuffer tBuffer = ByteBuffer.allocate(16);
+        tBuffer.putLong(timestamp);
+        JungleTree tree = jungle.getTreeByName(_board);
+        Either<Error, JungleTreeEditor> either = null;
+        do {
+            DefaultNodePath path = new DefaultNodePath();
+            path = path.add(Integer.parseInt(_uuid));
+
+            JungleTreeEditor editor = tree.getTreeEditor();
+            NodeEditor e = new NodeEditor() {
+                public Either<Error, LoggingNode> edit(TreeNode node) {
+                    LoggingNode logNode = wrap(node, new DefaultOperationLog());
+                    logNode = logNode.getAttributes().put("author", ByteBuffer.wrap(_author.getBytes())).b();
+                    logNode = logNode.getAttributes().put("mes", ByteBuffer.wrap(_message.getBytes())).b();
+                    logNode = logNode.getAttributes().put("key", ByteBuffer.wrap(_editKey.getBytes())).b();
+                    logNode = logNode.getAttributes().put("timestamp", tBuffer).b();
+                    return DefaultEither.newB(logNode);
+                }
+
+                @Override
+                public LoggingNode wrap(TreeNode node, OperationLog op) {
+                    return new LoggingNode(node, op);
+                }
+            };
+            either = editor.edit(path, e);
+            if (either.isA()) {
+                throw new IllegalStateException();
+            }
+            editor = either.b();
+            either = editor.success();
+        } while (either.isA());
+        renewTime = timestamp;
+    }
+
+    public Iterable<BoardMessage> getFolder(String _boardName, String _nodeNum) {
+        DefaultNodePath path = new DefaultNodePath();
+        System.out.println(_nodeNum.substring(0, 1));
+        String[] nums = _nodeNum.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+        JungleTree tree = jungle.getTreeByName(_boardName);
+        TreeNode node = tree.getRootNode();
+        requestCounter.incrementAndGet();
+
+        DefaultTraverser traverser = new DefaultTraverser();
+        DefaultEvaluator evaluator = new DefaultEvaluator(path);
+        Either<Error, Traversal> ret = traverser.traverse(node, evaluator);
+        if (ret.isA()) {
+            Assert.fail();
+        }
+
+        Traversal traversal = ret.b();
+        TreeNode target = traversal.destination();
+        Children chs = target.getChildren();
+
+        final AtomicInteger counter = new AtomicInteger(0);
+        IterableConverter.Converter<BoardMessage, TreeNode> converter = new IterableConverter.Converter<BoardMessage, TreeNode>() {
+            public BoardMessage conv(TreeNode _b) {
+                String uuid = Integer.toString(counter.get());
+                String message = new String(_b.getAttributes().get("mes").array());
+                counter.incrementAndGet();
+                return new BoardMessageImpl(null, message, uuid);
+            }
+        };
+        return new IterableConverter<BoardMessage, TreeNode>(chs, converter);
+    }
+
+    public boolean compare(TreeNode compareNode, String compareAttribute) {
+        String labName = compareNode.getAttributes().getString("mes");
+        if (labName.equals(compareAttribute))
+            return true;
+
+        for (int loopCount = 0; compareNode.getAttributes().getString("mes" + loopCount) != null; loopCount++) {
+            labName = compareNode.getAttributes().getString("mes" + loopCount);
+            if (labName.equals(compareAttribute))
+                return true;
+        }
+
+        return false;
+    }
+
+    public int getRequestNum() {
+        return requestCounter.get();
+    }
+
+    private static class BoardMessageImpl implements BoardMessage {
+        private final String author;
+        private final String message;
+        private final String uuid;
+
+        public BoardMessageImpl(String _author, String _message, String _uuid) {
+            author = _author;
+            message = _message;
+            uuid = _uuid;
+        }
+
+        public String getAuthor() {
+            return author;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public String getUUID() {
+            return uuid;
+        }
+
+    }
+
+    public String sanitize(String str) {
+        if (str == null) {
+            return str;
+        }
+        str = str.replaceAll("&", "&amp;");
+        str = str.replaceAll("<", "&lt;");
+        str = str.replaceAll(">", "&gt;");
+        str = str.replaceAll("\"", "&quot;");
+        str = str.replaceAll("'", "&#39;");
+        return str;
+    }
+
+    @Override
+    public GetAttributeImp getAttribute(String _bname, String _path, String revisionStr) {
+        DefaultNodePath path = new DefaultNodePath();
+        String[] nums = _path.split(",");
+        for (String num : nums) {
+            if (!num.equals("-1"))
+                path = path.add(Integer.parseInt(num));
+        }
+
+        JungleTree tree = jungle.getTreeByName(_bname);
+        TreeNode node;
+        if (revisionStr.equals("-1")) {
+            node = tree.getRootNode();
+        } else {
+            Long revision = Long.parseLong(revisionStr);
+            JungleTree oldTree = tree.getOldTree(revision).b();
+            node = oldTree.getRootNode();
+        }
+
+        DefaultTraverser traverser = new DefaultTraverser();
+        DefaultEvaluator evaluator = new DefaultEvaluator(path);
+        Either<Error, Traversal> ret = traverser.traverse(node, evaluator);
+        if (ret.isA()) {
+            Assert.fail();
+        }
+
+        Traversal traversal = ret.b();
+        TreeNode target = traversal.destination();
+        return new GetAttributeImp(target);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/RequestNumCheckServlet.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,36 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.NetworkBulletinBoard;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
+
+
+public class RequestNumCheckServlet extends HttpServlet
+{
+	private final NetworkBulletinBoard bbs;
+	private static final long serialVersionUID = 1L;
+	
+	public RequestNumCheckServlet(NetworkBulletinBoard _bbs)
+	{
+		bbs = _bbs;
+	}
+	
+	public void doGet(HttpServletRequest _req,HttpServletResponse _res)
+	{
+		int num = bbs.getRequestNum();
+		
+		try{
+			PrintWriter pw = _res.getWriter();
+			pw.write(Integer.toString(num));
+			pw.flush();
+		}catch(Exception _e){
+			_res.setStatus(500);
+		}
+		
+		
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/ShowMessageWithTimeStampServlet.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,65 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network;
+
+import jp.ac.u_ryukyu.ie.cr.jungle.bbs.GetAttributeImp;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.NetworkBulletinBoard;
+import org.eclipse.jetty.util.thread.ThreadPool;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+public class ShowMessageWithTimeStampServlet extends HttpServlet {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+    private final jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.NetworkBulletinBoard bbs;
+    private final String createBoardMessagePath;
+
+    private static final String PARAM_BOARD_NAME = "bname";
+    private final String editMessagePath;
+
+    public ShowMessageWithTimeStampServlet(NetworkBulletinBoard _bbs,
+                                           String _createBoardMessagePath, String _editMessagePath, ThreadPool thp) {
+        bbs = _bbs;
+        createBoardMessagePath = _createBoardMessagePath;
+        editMessagePath = _editMessagePath;
+    }
+
+    public void doGet(HttpServletRequest _req, HttpServletResponse _res) {
+        final String bname = (_req.getParameter(PARAM_BOARD_NAME));
+        try {
+            _res.setCharacterEncoding("UTF-8");
+            printBoard(bname, _res.getWriter());
+        } catch (Exception _e) {
+            _res.setStatus(500);
+        }
+    }
+
+    private void printBoard(String _bname, PrintWriter _pw) throws Exception {
+        _pw.write("<html><body>\n");
+        _pw.write("<h1>" + bbs.sanitize(_bname) + "</h1>\n");
+        _pw.write("<p>Latest renew time : " + bbs.getRenewTime(_bname)
+                + "</p>\n");
+        ;
+
+        _pw.write("<form action='" + createBoardMessagePath + "' method='POST'\n");
+        _pw.write("<p>Author : <input type='text' name='author'/> <input type='hidden' name='bname' value='" + bbs.sanitize(_bname) + "'/> EditKey : <input type='textarea' name='key'/></p>\n");
+        _pw.write("<p>Message<br/> <input type='textarea' name='msg'/> </p>\n");
+        _pw.write("<p><input type='submit' value='submit'/></p>\n");
+
+        GetAttributeImp attribute = bbs.getAttribute(_bname, "[-1]", "0");
+        Iterator<String> keys = attribute.getKeys();
+
+        while (keys.hasNext()) {
+            String key = keys.next();
+            String mesage = attribute.getMessage(key);
+            _pw.write("<p>" + key + " = " + mesage + "</p>\n");
+        }
+        _pw.write("<p><a href='" + editMessagePath + "?bname=" + bbs.sanitize(_bname) + "&uuid=-1,0" + "'>edit" + "</a></p>");
+        _pw.write("</body></html>");
+        _pw.flush();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/codesegment/LogPutCodeSegment.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,20 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network.codesegment;
+
+import alice.codesegment.CodeSegment;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.operations.NetworkTreeOperationLog;
+
+
+public class LogPutCodeSegment extends CodeSegment{
+
+	NetworkTreeOperationLog log;
+	
+	public LogPutCodeSegment(NetworkTreeOperationLog _log) {
+		log = _log;
+	}
+	
+	@Override
+	public void run() {
+		ods.put("log", log);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/codesegment/LogUpdateCodeSegment.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,48 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network.codesegment;
+
+import alice.codesegment.CodeSegment;
+import alice.datasegment.CommandType;
+import alice.datasegment.Receiver;
+import jp.ac.u_ryukyu.ie.cr.jungle.JungleTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.Either;
+import jp.ac.u_ryukyu.ie.cr.jungle.util.Error;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.BulletinBoardJungleManager;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.operations.NetworkTreeOperationLog;
+
+import java.util.List;
+
+public class LogUpdateCodeSegment extends CodeSegment {
+	
+	Receiver log = ids.create(CommandType.TAKE);
+	Receiver clist = ids.create(CommandType.PEEK);
+	
+	public LogUpdateCodeSegment() {
+		log.setKey("log");
+		clist.setKey("_CLIST");;
+	}
+	
+	public LogUpdateCodeSegment(int index) {
+		log.setKey("log", index);
+		clist.setKey("_CLIST");;
+	}
+	
+	public void run() {
+		int index = log.index;
+		new jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.codesegment.LogUpdateCodeSegment();
+		NetworkTreeOperationLog netLog = log.asClass(NetworkTreeOperationLog.class);
+		@SuppressWarnings("unchecked")
+		List<String> list = clist.asClass(List.class);
+		for (String node : list) {
+			if (!node.equals(log.from)) {
+				ods.put(node, log.key, log.getVal());
+			}
+		}
+		if (!log.from.equals("local")) {
+			Either<Error, JungleTreeEditor> either = BulletinBoardJungleManager.update(netLog);
+			if(either.isA()) {
+				new jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.codesegment.LogUpdateCodeSegment(index);
+				throw new IllegalStateException();				
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/codesegment/StartBBSCodeSegment.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,101 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network.codesegment;
+
+import alice.codesegment.CodeSegment;
+import alice.datasegment.CommandType;
+import alice.datasegment.Receiver;
+import jp.ac.u_ryukyu.ie.cr.jungle.bbs.*;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.NetworkBulletinBoard;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.NetworkJungleBulletinBoard;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.RequestNumCheckServlet;
+import jp.ac.u_ryukyu.ie.cr.jungleNetwork.bbs.codesegment.LogUpdateCodeSegment;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.thread.ThreadPool;
+
+import javax.servlet.Servlet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StartBBSCodeSegment extends CodeSegment {
+
+    int bbsPort = 8080;
+    Receiver host = ids.create(CommandType.PEEK);
+    private Pattern pattern = Pattern.compile("^(node|cli)([0-9]+)$");
+    private String[] args;
+    boolean persistentFlag = false;
+
+    public StartBBSCodeSegment(String[] _args, int p) {
+        args = _args;
+        bbsPort = p;
+        host.setKey("host");	
+    }
+
+    public StartBBSCodeSegment() {
+        args = null;
+        host.setKey("host");	
+    }
+
+    @Override
+    public void run() {
+        String name = host.asString();
+        Matcher matcher = pattern.matcher(name);
+        matcher.find();
+        //		String type = matcher.group(1);
+        for(String arg: args) {
+            if(arg.equals("-persistent")){
+                persistentFlag = true;
+            }
+        }
+        NetworkBulletinBoard cassaBBS = null;
+        if(persistentFlag) {
+            System.out.println("log loading...");
+            cassaBBS = NetworkJungleBulletinBoard.NewPersistentJungle(name);
+            cassaBBS.init();
+        } else {
+            cassaBBS = new NetworkJungleBulletinBoard(name);
+            cassaBBS.init();
+        }
+
+        System.out.println("StartBBSCodeSegment");
+        System.out.println("name : "+ name);
+        /* Jetty registration */
+        String createBoardMessagePath = "/createBoardMessage";
+        String createBoardPath = "/createBoard";
+        String editMessagePath = "/editMessage";
+        String showBoardMessagePath = "/showBoardMessage";
+
+
+        Server serv = new Server(bbsPort);
+        ThreadPool thp = serv.getThreadPool();
+        Servlet createBoardMessage = new CreateBoardMessageServlet(cassaBBS);
+        Servlet createBoard = new CreateBoardServlet(cassaBBS);
+        Servlet editBoardMessage = new EditMessageServlet(cassaBBS);
+        Servlet index = new ShowBoardsServlet(cassaBBS,createBoardPath,showBoardMessagePath);
+        Servlet board = new ShowBoardMessageServlet(cassaBBS,createBoardMessagePath,editMessagePath);
+        //Servlet board = new ShowMessageWithTimeStampServlet(cassaBBS,createBoardMessagePath,thp);
+
+        ServletHandler context = new ServletHandler();
+        context.addServletWithMapping(new ServletHolder(createBoardMessage),createBoardMessagePath);
+        context.addServletWithMapping(new ServletHolder(createBoard),createBoardPath);
+        context.addServletWithMapping(new ServletHolder(editBoardMessage),editMessagePath);
+        context.addServletWithMapping(new ServletHolder(index),"/");
+        context.addServletWithMapping(new ServletHolder(board),showBoardMessagePath);
+        /* 
+         * For write benchmark 
+         */
+        String editMessageUseGetPath = "/editMessageUseGet";
+        Servlet editMessageUseGet = new EditMessageUseGetServlet(cassaBBS);
+        context.addServletWithMapping(new ServletHolder(editMessageUseGet), editMessageUseGetPath);
+        String requestNumCheckPath = "/requestNum";
+        Servlet requestNumCheckServlet = new RequestNumCheckServlet(cassaBBS);
+        context.addServletWithMapping(new ServletHolder(requestNumCheckServlet), requestNumCheckPath);
+
+        serv.setHandler(context);
+        try {
+            serv.start();
+        } catch (Exception e) { }
+        new LogUpdateCodeSegment();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/io/NullOutputStream.java	Mon Jun 27 05:06:19 2016 +0900
@@ -0,0 +1,15 @@
+package jp.ac.u_ryukyu.ie.cr.bbs.network.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class NullOutputStream extends OutputStream {
+	
+	public NullOutputStream() {
+	}
+
+	@Override
+	public void write(int arg0) throws IOException {
+	}
+
+}