view src/main/java/jp/ac/u_ryukyu/ie/cr/jungle/transaction/editor/jungleTreeEditor/RedBlackJungleTreeEditor.java @ 308:201cc75a9984

change Red Black Tree Edit Path Extends
author tatsuki
date Thu, 26 Jan 2017 15:23:25 +0900
parents 1a5f3d3f3437
children f8e75ef7ac5d
line wrap: on
line source

package jp.ac.u_ryukyu.ie.cr.jungle.transaction.editor.jungleTreeEditor;

import jp.ac.u_ryukyu.ie.cr.jungle.data.list.List;
import jp.ac.u_ryukyu.ie.cr.jungle.store.logger.DefaultTreeOperationLog;
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.logger.TreeOperationLog;
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.nodepath.PathType;
import jp.ac.u_ryukyu.ie.cr.jungle.store.operations.DefaultTreeOperation;
import jp.ac.u_ryukyu.ie.cr.jungle.store.operations.NodeOperation;
import jp.ac.u_ryukyu.ie.cr.jungle.store.operations.TreeOperation;
import jp.ac.u_ryukyu.ie.cr.jungle.store.trasnformer.*;
import jp.ac.u_ryukyu.ie.cr.jungle.transaction.editor.treeEditor.TreeEditor;
import jp.ac.u_ryukyu.ie.cr.jungle.transaction.manager.TransactionManager;
import jp.ac.u_ryukyu.ie.cr.jungle.transaction.node.TreeNode;
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.jungle.util.IterableConverter;

import java.nio.ByteBuffer;

import static jp.ac.u_ryukyu.ie.cr.jungle.util.Error.JungleTreeError.INVALID_ARGUMENT;
import static jp.ac.u_ryukyu.ie.cr.jungle.util.Error.JungleTreeError.NOT_USE_METHOD;


public class RedBlackJungleTreeEditor implements JungleTreeEditor {
    private final TransactionManager txManager;
    private final TreeNode root;
    private final TreeEditor editor;
    private final TreeOperationLog log;
    private final List<TreeNode> editedNodeList;
    private final String balanceKey;

    public RedBlackJungleTreeEditor(TreeNode root, String balanceKey, TransactionManager txManager, TreeEditor editor) {
        this(root, balanceKey, txManager, editor, new DefaultTreeOperationLog(), new List<>());
    }


    public RedBlackJungleTreeEditor(TreeNode newNode, String balanceKey, TransactionManager txManager, TreeEditor editor, TreeOperationLog log, List<TreeNode> editedNodeList) {
        this.root = newNode;
        this.txManager = txManager;
        this.editor = editor;
        this.log = log;
        this.editedNodeList = editedNodeList;
        this.balanceKey = balanceKey;
    }


    private Either<Error, JungleTreeEditor> _edit(final NodePath _path, NodeEditor _e) {
        Either<Error, LoggingNode> editEither = editor.edit(root, _path, _e);

        if (editEither.isA()) {
            return DefaultEither.newA(editEither.a());
        }

        LoggingNode newLogging = editEither.b();
        OperationLog newLog = newLogging.getOperationLog();
        TreeNode newNode = newLogging.getWrap();
        TreeNode editedNode = newLogging.getEditedNode();
        List<TreeNode> newEditendNodeList = editedNodeList.add(0, editedNode);
        IterableConverter.Converter<TreeOperation, NodeOperation> converter = new IterableConverter.Converter<TreeOperation, NodeOperation>() {
            @Override
            public TreeOperation conv(NodeOperation _b) {
                return new DefaultTreeOperation(_path, _b);
            }
        };

        Iterable<TreeOperation> iterable = new IterableConverter<>(newLog, converter);
        DefaultTreeOperationLog treeOperationLog = new DefaultTreeOperationLog(iterable, newLog.length());
        TreeOperationLog newTreeOpLog = log.append(treeOperationLog);
        JungleTreeEditor newEditor = new RedBlackJungleTreeEditor(newNode, balanceKey, txManager, editor, newTreeOpLog, newEditendNodeList);
        return DefaultEither.newB(newEditor);
    }

    /**
     * 赤黒木なのでNodeを入れた後は回転処理が行われるので
     * Pathは無視する
     * Pathがあるのはインターフェスで定義されているmethodに合わせるため
     */
    @Override
    public Either<Error, JungleTreeEditor> addNewChildAndPutAttribute(NodePath path, int pos, String key, ByteBuffer value) {
        path = new DefaultNodePath(-2);
        AppendChildAndPutAttribute appendChildAndPutAttribute = new AppendChildAndPutAttribute(key, value, pos);
        return _edit(path, appendChildAndPutAttribute);
    }

    @Override
    public Either<Error, JungleTreeEditor> addNewChildAt(NodePath path, int _pos) {
        ByteBuffer value = ByteBuffer.wrap("defaultValue".getBytes());
        path = new DefaultNodePath(-2);
        return addNewChildAndPutAttribute(path, 0, balanceKey, value);
    }

    @Override
    public Either<Error, JungleTreeEditor> deleteChildAt(NodePath path, int pos) {
        String key = path.getKey();
        if (!key.equals(balanceKey))
            return DefaultEither.newA(INVALID_ARGUMENT);
        ByteBuffer value = path.getValue();
        RedBlackTreeDeleteChildAt deleteChildAt = new RedBlackTreeDeleteChildAt(key, value);
        return _edit(path, deleteChildAt);
    }

    @Override
    public Either<Error, JungleTreeEditor> putAttribute(NodePath path, String key, ByteBuffer value) {
        if (key.equals(balanceKey))
            return DefaultEither.newA(INVALID_ARGUMENT);
        if (path.getPathType() != PathType.RedBlack)
            return DefaultEither.newA(INVALID_ARGUMENT);
        NodeEditor editor = new PutAttribute(key, value);
        NodePath newParh = path.add(-1); //回転処理を行わないで木の複製を行う設定のPathに変えている… ダサい…
        return _edit(newParh, editor);
    }

    @Override
    public Either<Error, JungleTreeEditor> deleteAttribute(NodePath _path, String _key) {
        if (_key.equals(balanceKey))
            return DefaultEither.newA(INVALID_ARGUMENT);
        DeleteAttribute deleteAttribute = new DeleteAttribute(_key);
        return _edit(_path, deleteAttribute);
    }


    @Override
    public Either<Error, JungleTreeEditor> moveChild(NodePath path, int childNum, String move) {
        return DefaultEither.newA(NOT_USE_METHOD); //赤黒木だから使わない
    }

    @Override
    public Either<Error, JungleTreeEditor> replaceNewRootNode() {
        return DefaultEither.newA(NOT_USE_METHOD); // 赤黒木だから使わない
    }

    @Override
    public Either<Error, JungleTreeEditor> edit(NodePath _path, NodeEditor _editor) {
        return _edit(_path, _editor);
    }


    @Override
    public Either<Error, JungleTreeEditor> success() {
        Either<Error, TransactionManager> either = txManager.commit(root, log, editedNodeList);
        if (either.isA()) {
            return DefaultEither.newA(either.a());
        }

        TransactionManager newTxManager = either.b();
        JungleTreeEditor newTreeEditor = new RedBlackJungleTreeEditor(root, balanceKey, newTxManager, editor);

        return DefaultEither.newB(newTreeEditor);
    }

    @Override
    public Either<Error, JungleTreeEditor> flushSuccess() {
        return null;
    }

}