view src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/bbs/NetworkJungleBulletinBoard.java @ 8:766f7668521f

commit
author tatsuki
date Thu, 02 Feb 2017 23:05:59 +0900
parents src/main/java/jp/ac/u_ryukyu/ie/cr/bbs/network/NetworkJungleBulletinBoard.java@5acde010c6db
children 2890ae6b1aef
line wrap: on
line source

package jp.ac.u_ryukyu.ie.cr.bbs.network.bbs;


import jp.ac.u_ryukyu.ie.cr.bbs.local.bbs.BoardMessage;
import jp.ac.u_ryukyu.ie.cr.bbs.local.bbs.GetAttributeImp;
import jp.ac.u_ryukyu.ie.cr.bbs.local.bbs.IterableConverter;
import jp.ac.u_ryukyu.ie.cr.jungle.Jungle;
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.logger.LoggingNode;
import jp.ac.u_ryukyu.ie.cr.jungle.store.logger.OperationLog;
import jp.ac.u_ryukyu.ie.cr.jungle.store.nodepath.DefaultNodePath;
import jp.ac.u_ryukyu.ie.cr.jungle.store.nodepath.NodePath;
import jp.ac.u_ryukyu.ie.cr.jungle.store.trasnformer.NodeEditor;
import jp.ac.u_ryukyu.ie.cr.jungle.transaction.editor.jungleTreeEditor.JungleTreeEditor;
import jp.ac.u_ryukyu.ie.cr.jungle.transaction.node.Default.DefaultTreeNode;
import jp.ac.u_ryukyu.ie.cr.jungle.transaction.node.TreeNode;
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.tree.JungleTree;
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.Error;
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);
        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.getLocalJungleTreeEditor();
            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.getJungleTreeEditor();
        NodePath 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.getJungleTreeEditor();
        either = editor.addNewChildAt(root, 0);
        if (either.isA()) {
            throw new IllegalStateException();
        }
        editor = either.b();

        NodeEditor e = new NodeEditor() {
            ByteBuffer tBuffer2 = ByteBuffer.allocate(16);

            Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                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 Either<Error, LoggingNode> edit(TreeNode _e) {
                LoggingNode logNode = wrap(_e);
                return _edit(logNode);
            }

            private LoggingNode wrap(TreeNode node) {
                return new LoggingNode(node);
            }

            @Override
            public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                return new LoggingNode(newRoot, editedNode, operationLog);
            }

        };

        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.getJungleTreeEditor();
            either = editor.addNewChildAt(path, size);
            if (either.isA()) {
                throw new IllegalStateException();
            }
            editor = either.b();

            NodeEditor e = new NodeEditor() {

                Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                    logNode = logNode.getAttributes().put("mes", ByteBuffer.wrap(_message.getBytes())).b();
                    logNode = logNode.getAttributes().put("timestamp", tBuffer).b();
                    return DefaultEither.newB(logNode);
                }

                @Override
                public Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }

            };
            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.getJungleTreeEditor();
            either = editor.addNewChildAt(path, size);
            if (either.isA()) {
                throw new IllegalStateException();
            }
            editor = either.b();

            NodeEditor e = new NodeEditor() {
                Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                    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 Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }
            };
            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.getJungleTreeEditor();
            NodeEditor e = new NodeEditor() {
                Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                    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 Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }

            };
            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.getJungleTreeEditor();
            NodeEditor e = new NodeEditor() {
                String str;

                Either<Error, LoggingNode> _edit(LoggingNode logNode) {                    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 Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }

            };
            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.getJungleTreeEditor();
            NodeEditor e = new NodeEditor() {
                Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                    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 Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }

            };
            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.getJungleTreeEditor();

            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.getJungleTreeEditor();
            NodeEditor e = new NodeEditor() {
                Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                    TreeNode node = logNode.getWrap();
                    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 Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }

            };
            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.getJungleTreeEditor();
            NodeEditor e = new NodeEditor() {
                Either<Error, LoggingNode> _edit(LoggingNode logNode) {
                    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 Either<Error, LoggingNode> edit(TreeNode _e) {
                    LoggingNode logNode = wrap(_e);
                    return _edit(logNode);
                }

                private LoggingNode wrap(TreeNode node) {
                    return new LoggingNode(node);
                }

                @Override
                public LoggingNode wrap(TreeNode newRoot, TreeNode editedNode, OperationLog operationLog) {
                    return new LoggingNode(newRoot, editedNode, operationLog);
                }

            };
            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;
    }

    public GetAttributeImp getAttribute(String _bname, String nodePath, String revisionStr) {
        DefaultNodePath path = createNodePath(nodePath);
        JungleTree tree = jungle.getTreeByName(_bname);
        Either<Error, TreeNode> either = tree.getNodeOfPath(path);
        if (either.isA())
            return new GetAttributeImp(new DefaultTreeNode());
        TreeNode node = either.b();
        return new GetAttributeImp(node);
    }

    private DefaultNodePath createNodePath(String nodePath) {
        DefaultNodePath path = new DefaultNodePath();
        String[] nums = nodePath.split(",");
        for (String num : nums) {
            if (num.equals("-1"))
                continue;
            path = path.add(Integer.parseInt(num));
        }
        return path;
    }

}