Java tutorial
/* 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; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.geogit.api.AbstractGeoGitOp; import org.geogit.api.Bucket; import org.geogit.api.Node; import org.geogit.api.NodeRef; import org.geogit.api.ObjectId; import org.geogit.api.RevObject; import org.geogit.api.RevObject.TYPE; import org.geogit.api.RevTree; import org.geogit.api.plumbing.LsTreeOp.Strategy; import org.geogit.repository.StagingArea; import org.geogit.storage.ObjectDatabase; import org.geogit.storage.StagingDatabase; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; import com.google.inject.Inject; /** * Moves the {@link #setObjectRef(Supplier) specified object} from the {@link StagingArea index * database} to the permanent {@link ObjectDatabase object database}, including any child reference, * or from the repository database to the index database if {@link #setToIndex} is set to * {@code true}. */ public class DeepMove extends AbstractGeoGitOp<ObjectId> { private boolean toIndex; private ObjectDatabase odb; private StagingDatabase index; private Supplier<Node> objectRef; private Supplier<ObjectId> objectId; private Supplier<Iterator<Node>> nodesToMove; /** * Constructs a new instance of the {@code DeepMove} operation with the specified parameters. * * @param odb the repository object database * @param index the staging database */ @Inject public DeepMove(ObjectDatabase odb, StagingDatabase index) { this.odb = odb; this.index = index; } /** * @param toIndex if {@code true} moves the object from the repository's object database to the * index database instead * @return {@code this} */ public DeepMove setToIndex(boolean toIndex) { this.toIndex = toIndex; return this; } /** * @param id the id of the object to move, mutually exclusive with * {@link #setObjectRef(Supplier)} * @return */ public DeepMove setObject(Supplier<ObjectId> id) { this.objectId = id; this.objectRef = null; this.nodesToMove = null; return this; } /** * @param objectRef the object to move from the origin database to the destination one, mutually * exclusive with {@link #setObject(Supplier)} * @return {@code this} */ public DeepMove setObjectRef(Supplier<Node> objectRef) { this.objectRef = objectRef; this.objectId = null; this.nodesToMove = null; return this; } public DeepMove setObjects(Supplier<Iterator<Node>> nodesToMove) { this.nodesToMove = nodesToMove; this.objectId = null; this.objectRef = null; return this; } /** * Executes a deep move using the supplied {@link Node}. * * @return the {@link ObjectId} of the moved object, or {@code null} if {@link #setObjects} was * used and hence no such information it available */ @Override public ObjectId call() { ObjectDatabase from = toIndex ? odb : index; ObjectDatabase to = toIndex ? index : odb; Set<ObjectId> metadataIds = new HashSet<ObjectId>(); final ObjectId ret; if (objectRef != null) { Node ref = objectRef.get(); ret = ref.getObjectId(); deepMove(ref, from, to, metadataIds); } else if (objectId != null) { ObjectId id = objectId.get(); moveObject(id, from, to); ret = id; } else if (nodesToMove != null) { moveObjects(from, to, nodesToMove, metadataIds); ret = null; } else { throw new IllegalStateException("No object supplied to be moved"); } for (ObjectId metadataId : metadataIds) { moveObject(metadataId, from, to); } return ret; } private void moveObjects(final ObjectDatabase from, final ObjectDatabase to, Supplier<Iterator<Node>> nodesToMove, final Set<ObjectId> metadataIds) { Function<Node, ObjectId> asIds = new Function<Node, ObjectId>() { @Override public ObjectId apply(Node input) { return input.getObjectId(); } }; Function<Node, RevObject> asObjects = new Function<Node, RevObject>() { @Override public RevObject apply(Node input) { if (input.getMetadataId().isPresent()) { metadataIds.add(input.getMetadataId().get()); } return from.get(input.getObjectId()); } }; Iterator<Node> iterator; iterator = nodesToMove.get(); if (iterator.hasNext()) { to.putAll(Iterators.transform(iterator, asObjects)); iterator = nodesToMove.get(); from.deleteAll(Iterators.transform(iterator, asIds)); } } /** * Transfers the object referenced by {@code objectRef} from the given object database to the * given objectInserter as well as any child object if {@code objectRef} references a tree. */ private void deepMove(final Node objectRef, final ObjectDatabase from, final ObjectDatabase to, Set<ObjectId> metadataIds) { if (objectRef.getMetadataId().isPresent()) { metadataIds.add(objectRef.getMetadataId().get()); } final ObjectId objectId = objectRef.getObjectId(); if (TYPE.TREE.equals(objectRef.getType())) { moveTree(objectId, from, to, metadataIds); } else { moveObject(objectId, from, to); } } private void moveTree(final ObjectId treeId, final ObjectDatabase from, final ObjectDatabase to, final Set<ObjectId> metadataIds) { Supplier<Iterator<NodeRef>> refs = command(LsTreeOp.class).setReference(treeId.toString()) .setStrategy(Strategy.DEPTHFIRST_ONLY_FEATURES); Supplier<Iterator<Node>> nodes = Suppliers.compose(new Function<Iterator<NodeRef>, Iterator<Node>>() { @Override public Iterator<Node> apply(Iterator<NodeRef> input) { return Iterators.transform(input, new Function<NodeRef, Node>() { @Override public Node apply(NodeRef input) { return input.getNode(); } }); } }, refs); // move all features, recursively as given by the LsTreeOp strategy moveObjects(from, to, nodes, metadataIds); // collect all subtree and bucket ids here to delete them from the origin db final Set<ObjectId> alltreeIds = Sets.newTreeSet(); Predicate<RevTree> collectIds = new Predicate<RevTree>() { @Override public boolean apply(RevTree input) { alltreeIds.add(input.getId()); return true; } }; // iterator that traverses the tree,all its subtrees, an bucket trees Iterator<RevTree> allSubtreesAndBuckets = new AllTrees(treeId, from); allSubtreesAndBuckets = Iterators.filter(allSubtreesAndBuckets, collectIds); to.putAll(allSubtreesAndBuckets); from.deleteAll(alltreeIds.iterator()); } private static class AllTrees extends AbstractIterator<RevTree> { private RevTree tree; private ObjectDatabase from; private Iterator<Node> trees; private Iterator<Bucket> buckets; private Iterator<RevTree> bucketTrees; public AllTrees(ObjectId id, ObjectDatabase from) { this.from = from; this.tree = from.getTree(id); this.trees = Iterators.emptyIterator(); if (tree.trees().isPresent()) { trees = tree.trees().get().iterator(); } buckets = Iterators.emptyIterator(); if (tree.buckets().isPresent()) { buckets = tree.buckets().get().values().iterator(); } bucketTrees = Iterators.emptyIterator(); } @Override protected RevTree computeNext() { if (tree != null) { RevTree ret = tree; tree = null; return ret; } if (trees.hasNext()) { ObjectId objectId = trees.next().getObjectId(); return from.getTree(objectId); } if (bucketTrees.hasNext()) { return bucketTrees.next(); } if (buckets.hasNext()) { bucketTrees = new AllTrees(buckets.next().id(), from); return computeNext(); } return endOfData(); } } private void moveObject(RevObject object, ObjectDatabase from, ObjectDatabase to) { to.put(object); from.delete(object.getId()); } private void moveObject(final ObjectId objectId, final ObjectDatabase from, final ObjectDatabase to) { RevObject object = from.get(objectId); moveObject(object, from, to); } }