view src/main/java/app/bbs/NetworkJungleBulletinBoard.java @ 192:3202a2a427b1 default tip

bug fix
author tatsuki
date Tue, 20 Jan 2015 09:30:59 +0900
parents 5d0734fd859d
children
line wrap: on
line source

package app.bbs;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;

import alice.jungle.core.NetworkDefaultJungle;
import alice.jungle.persistent.AliceJournal;
import alice.jungle.persistent.NetworkJournal;
import alice.jungle.persistent.PersistentJournal;
import alice.jungle.transaction.JungleUpdater;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.Jungle;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTree;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTreeEditor;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.bbs.BoardMessage;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.bbs.GetAttributeImp;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Children;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeList;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeListReader;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNodePath;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultTreeEditor;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.TreeNode;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.DefaultOperationLog;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.LoggingNode;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.OperationLog;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.NodeEditor;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.DefaultEvaluator;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.DefaultTraverser;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.Traversal;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultEither;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.IterableConverter;
import junit.framework.Assert;

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 _nodeNum) {
    JungleTree tree = jungle.getTreeByName(_board);
    if (tree == null) {
      throw new IllegalStateException();
    }

    DefaultNodePath path = new DefaultNodePath();
    try {
      for (int count = 0; _nodeNum.substring(count, count + 1) != null; count++) {
        if (!_nodeNum.substring(count, count + 1).equals("/"))
          path = path.add(Integer.parseInt(_nodeNum.substring(count, count + 1)));
      }
    } catch (Exception _e) {
    }
    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();
      // TraversableNodeWrapper<Node> traversable = new
      // TraversableNodeWrapper<Node>(node);
      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 _nodeNum, 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();
      try {
        for (int count = 0; _nodeNum.substring(count, count + 1) != null; count++) {
          if (!_nodeNum.substring(count, count + 1).equals("/"))
            path = path.add(Integer.parseInt(_nodeNum.substring(count, count + 1)));
        }
      } catch (Exception _e) {
      }
      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 _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;
    DefaultNodePath path = new DefaultNodePath();
    do {
      try {
        for (int count = 0; _uuid.substring(count, count + 1) != null; count++) {
          if (!_uuid.substring(count, count + 1).equals("/"))
            path = path.add(Integer.parseInt(_uuid.substring(count, count + 1)));
        }
      } catch (Exception _e) {
      }

      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 boardName, 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(boardName);
    Either<Error, JungleTreeEditor> either = null;
    DefaultNodePath path = new DefaultNodePath();
    do {
      try {
        for (int count = 0; _path.substring(count, count + 1) != null; count++) {
          if (!_path.substring(count, count + 1).equals("/"))
            path = path.add(Integer.parseInt(_path.substring(count, count + 1)));
        }
      } catch (Exception _e) {
      }

      JungleTreeEditor editor = tree.getTreeEditor();
      NodeEditor e = new NodeEditor() {
        public Either<Error, LoggingNode> edit(TreeNode node) {
          LoggingNode logNode = wrap(node, new DefaultOperationLog());
          // EnableNodeWrapper<T> node = _e.getWrap();
          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();
    do {
      try {
        for (int count = 0; _path.substring(count, count + 1) != null; count++) {
          if (!_path.substring(count, count + 1).equals("/"))
            path = path.add(Integer.parseInt(_path.substring(count, count + 1)));
        }
      } catch (Exception _e) {
      }

      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();
    do {
      try {
        for (int count = 0; _path.substring(count, count + 1) != null; count++) {
          if (!_path.substring(count, count + 1).equals("/"))
            path = path.add(Integer.parseInt(_path.substring(count, count + 1)));
        }
      } catch (Exception _e) {
        System.out.println("屑");
      }

      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();
    try {
      for (int count = 0; _nodeNum.substring(count, count + 1) != null; count++) {
        if (!_nodeNum.substring(count, count + 1).equals("/"))
          path = path.add(Integer.parseInt(_nodeNum.substring(count, count + 1)));
      }
    } catch (Exception _e) {
    }
    requestCounter.incrementAndGet();
    JungleTree tree = jungle.getTreeByName(_boardName);
    TreeNode node = tree.getRootNode();

    DefaultTraverser traverser = new DefaultTraverser();
    // TraversableNodeWrapper<Node> traversable = new
    // TraversableNodeWrapper<Node>(node);
    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;

    int loopCount = 0;
    for (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 _nodeNum, String revisionStr) {

    DefaultNodePath path = new DefaultNodePath();
    try {
      for (int count = 0; _nodeNum.substring(count, count + 1) != null; count++) {
        if (!_nodeNum.substring(count, count + 1).equals("/"))
          path = path.add(Integer.parseInt(_nodeNum.substring(count, count + 1)));
      }
    } catch (Exception _e) {
    }
    JungleTree tree = jungle.getTreeByName(_bname);
    System.out.println(tree.revision());
    Long revision = Long.parseLong(revisionStr);
    JungleTree oldTree = tree.getOldTree(revision).b();
    System.out.println(oldTree.revision());
    TreeNode 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);
  }
}