org.geogit.api.plumbing.diff.MutableTree.java Source code

Java tutorial

Introduction

Here is the source code for org.geogit.api.plumbing.diff.MutableTree.java

Source

/* Copyright (c) 2013 OpenPlans. All rights reserved.
 * This code is licensed under the BSD New License, available at the root
 * application directory.
 */
package org.geogit.api.plumbing.diff;

import static org.geogit.api.NodeRef.ROOT;
import static org.geogit.api.NodeRef.depth;
import static org.geogit.api.NodeRef.split;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.annotation.Nullable;

import org.geogit.api.Node;
import org.geogit.api.NodeRef;
import org.geogit.api.ObjectId;
import org.geogit.api.RevObject.TYPE;
import org.geogit.api.RevTree;
import org.geogit.api.RevTreeBuilder;
import org.geogit.storage.ObjectDatabase;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;

/**
 * A mutable data structure representing the state of a tree and its subtrees
 */
public class MutableTree implements Cloneable {

    private Node node;

    private Map<String, MutableTree> childTrees;

    public static final Ordering<NodeRef> DEEPEST_LAST_COMPARATOR = new Ordering<NodeRef>() {
        @Override
        public int compare(NodeRef o1, NodeRef o2) {

            int depth = Integer.valueOf(depth(o1.path())).compareTo(Integer.valueOf(depth(o2.path())));

            if (depth != 0) {
                return depth;
            }
            return o1.path().compareTo(o2.path());
        }
    };

    public static final Ordering<NodeRef> DEEPEST_FIRST_COMPARATOR = DEEPEST_LAST_COMPARATOR.reverse();

    private MutableTree(String name) {
        this(Node.tree(name, ObjectId.NULL, ObjectId.NULL));
    }

    private MutableTree(Node node) {
        this.node = node;
        this.childTrees = Maps.newTreeMap();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        toString(this, sb, 0);
        return sb.toString();
    }

    private void toString(MutableTree tree, StringBuilder sb, int indent) {
        Node node = tree.getNode();
        append(sb, node, indent);

        for (MutableTree c : tree.childTrees.values()) {
            toString(c, sb, indent + 1);
        }

    }

    private void append(StringBuilder sb, Node node, int indent) {
        sb.append(Strings.repeat("    ", indent)).append(node.getName()).append("->").append(node.getObjectId())
                .append(" (").append(node.getMetadataId()).append(")\n");
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof MutableTree)) {
            return false;
        }
        MutableTree other = (MutableTree) o;
        return node.equals(other.node) && node.getMetadataId().equals(other.node.getMetadataId())
                && childTrees.equals(other.childTrees);
    }

    public static MutableTree createFromRefs(final ObjectId rootId, final Supplier<Iterator<NodeRef>> refs) {
        return createFromRefs(rootId, refs.get());
    }

    public static MutableTree createFromRefs(final ObjectId rootId, @Nullable final NodeRef... treeRefs) {
        Iterator<NodeRef> refs = Iterators.emptyIterator();
        if (treeRefs != null) {
            refs = Lists.newArrayList(treeRefs).iterator();
        }
        return createFromRefs(rootId, refs);
    }

    public static MutableTree createFromRefs(final ObjectId rootId, final Iterator<NodeRef> treeRefs) {

        Function<NodeRef, String> keyFunction = new Function<NodeRef, String>() {

            @Override
            public String apply(@Nullable NodeRef input) {
                return input.path();
            }
        };

        ImmutableMap<String, NodeRef> treesByPath = Maps.uniqueIndex(treeRefs, keyFunction);

        return createFromPaths(rootId, treesByPath);
    }

    public static MutableTree createFromPaths(final ObjectId rootId, final Map<String, NodeRef> entries) {

        List<NodeRef> refsByDepth = Lists.newArrayList(entries.values());
        Collections.sort(refsByDepth, DEEPEST_LAST_COMPARATOR);

        MutableTree root = new MutableTree(Node.create(ROOT, rootId, ObjectId.NULL, TYPE.TREE));

        for (NodeRef entry : refsByDepth) {
            Node node = entry.getNode();
            String parentPath = entry.getParentPath();
            root.setChild(parentPath, node);
        }

        return root;
    }

    public Node getNode() {
        return node;
    }

    public void forceChild(final String parentPath, final Node treeNode) {
        ImmutableList<String> parentSteps = NodeRef.split(parentPath);
        MutableTree parent = this;
        for (String name : parentSteps) {
            MutableTree child = parent.childTrees.get(name);
            if (child == null) {
                child = new MutableTree(name);
                parent.childTrees.put(name, child);
            }
            parent = child;
        }

        MutableTree tree = parent.childTrees.get(treeNode.getName());
        if (tree == null) {
            tree = new MutableTree(treeNode);
            parent.childTrees.put(treeNode.getName(), tree);
        } else {
            tree.setNode(treeNode);
        }
    }

    public void setChild(String parentPath, Node node) {
        List<String> parentSteps = split(parentPath);
        setChild(parentSteps, node);
    }

    public void setChild(final List<String> parentPath, final Node node) {
        MutableTree parent;
        MutableTree child;
        if (parentPath.isEmpty()) {
            parent = this;
        } else {
            parent = getChild(parentPath);
        }

        child = parent.childTrees.get(node.getName());
        if (child == null) {
            child = new MutableTree(node);
            parent.childTrees.put(node.getName(), child);
        } else {
            child.setNode(node);
        }
    }

    public MutableTree getChild(String path) throws IllegalArgumentException {
        return getChild(NodeRef.split(path));
    }

    public MutableTree getChild(final List<String> path) throws IllegalArgumentException {
        Preconditions.checkArgument(!path.isEmpty());

        String directChildName = path.get(0);
        MutableTree child = childTrees.get(directChildName);
        if (child == null) {
            throw new IllegalArgumentException(
                    String.format("No child named %s exists: %s", directChildName, childTrees.keySet()));
        }
        if (path.size() == 1) {
            return child;
        }
        return child.getChild(path.subList(1, path.size()));
    }

    public SortedMap<String, MutableTree> getChildrenAsMap() {
        TreeMap<String, MutableTree> map = Maps.newTreeMap();
        asMap("", map);
        return map;
    }

    private void asMap(String parentPath, TreeMap<String, MutableTree> target) {
        for (MutableTree childTree : this.childTrees.values()) {
            String childTreePath = NodeRef.appendChild(parentPath, childTree.getNode().getName());
            target.put(childTreePath, childTree);
            childTree.asMap(childTreePath, target);
        }

    }

    @Nullable
    public MutableTree removeChild(String path) {
        ImmutableList<String> steps = NodeRef.split(path);
        MutableTree tree = this;

        for (Iterator<String> childNames = steps.iterator(); childNames.hasNext();) {
            String childName = childNames.next();
            MutableTree child = tree.childTrees.get(childName);
            if (child == null) {
                return null;
            }
            if (!childNames.hasNext()) {
                MutableTree removed = tree.childTrees.remove(childName);
                return removed;
            } else {
                tree = child;
            }
        }
        return null;
    }

    public void setNode(final Node newNode) {
        this.node = newNode;
    }

    public RevTree build(ObjectDatabase origin, ObjectDatabase target) {
        RevTree tree = RevTree.EMPTY;
        if (!node.getObjectId().isNull()) {
            tree = origin.getTree(node.getObjectId());
        }
        RevTreeBuilder builder = tree.builder(target).clearSubtrees();

        for (MutableTree childTree : this.childTrees.values()) {
            RevTree newChild = childTree.build(origin, target);
            target.put(newChild);
            Node oldNode = childTree.getNode();
            String name = oldNode.getName();
            ObjectId newObjectId = newChild.getId();
            ObjectId metadataId = oldNode.getMetadataId().or(ObjectId.NULL);
            Node newNode = Node.create(name, newObjectId, metadataId, TYPE.TREE);
            builder.put(newNode);
        }
        RevTree newTree = builder.build();
        if (!this.node.getObjectId().equals(newTree.getId())) {
            target.put(newTree);
            this.node = Node.create(node.getName(), newTree.getId(), node.getMetadataId().or(ObjectId.NULL),
                    TYPE.TREE);
        }

        return newTree;
    }

    @Override
    public MutableTree clone() {
        MutableTree clone = new MutableTree(node);
        for (MutableTree child : this.childTrees.values()) {
            clone.childTrees.put(child.getNode().getName(), child.clone());
        }
        return clone;
    }
}