return mergeNode(baseRoot, ourRoot, theirRootCopy, "/");
}
private NodeImpl mergeNode(Node baseNode, Node ourNode, Node theirNode,
String path) throws Exception {
MongoNodeDelta theirChanges = new MongoNodeDelta(new SimpleMongoNodeStore(),
MongoUtil.wrap(baseNode), MongoUtil.wrap(theirNode));
MongoNodeDelta ourChanges = new MongoNodeDelta(new SimpleMongoNodeStore(),
MongoUtil.wrap(baseNode), MongoUtil.wrap(ourNode));
NodeImpl stagedNode = (NodeImpl)theirNode; //new NodeImpl(path);
// Apply our changes.
stagedNode.getProperties().putAll(ourChanges.getAddedProperties());
stagedNode.getProperties().putAll(ourChanges.getChangedProperties());
for (String name : ourChanges.getRemovedProperties().keySet()) {
stagedNode.getProperties().remove(name);
}
for (Map.Entry<String, NodeState> entry : ourChanges.getAddedChildNodes().entrySet()) {
MongoNodeState nodeState = (MongoNodeState)entry.getValue();
stagedNode.addChildNodeEntry(nodeState.unwrap());
}
for (Map.Entry<String, NodeState> entry : ourChanges.getChangedChildNodes().entrySet()) {
if (!theirChanges.getChangedChildNodes().containsKey(entry.getKey())) {
MongoNodeState nodeState = (MongoNodeState)entry.getValue();
stagedNode.addChildNodeEntry(nodeState.unwrap());
}
}
for (String name : ourChanges.getRemovedChildNodes().keySet()) {
stagedNode.removeChildNodeEntry(name);
}
List<Conflict> conflicts = theirChanges.listConflicts(ourChanges);
// resolve/report merge conflicts
for (Conflict conflict : conflicts) {
String conflictName = conflict.getName();
String conflictPath = PathUtils.concat(path, conflictName);
switch (conflict.getType()) {
case PROPERTY_VALUE_CONFLICT:
throw new Exception(
"concurrent modification of property " + conflictPath
+ " with conflicting values: \""
+ ourNode.getProperties().get(conflictName)
+ "\", \""
+ theirNode.getProperties().get(conflictName));
case NODE_CONTENT_CONFLICT: {
if (ourChanges.getChangedChildNodes().containsKey(conflictName)) {
// modified subtrees
Node baseChild = baseNode.getChildNodeEntry(conflictName);
Node ourChild = ourNode.getChildNodeEntry(conflictName);
Node theirChild = theirNode.getChildNodeEntry(conflictName);
// merge the dirty subtrees recursively