+ private void mergeChildrenIntoModification(final ModifiedNode modification,
+ final Collection<? extends NormalizedNode<?, ?>> children, final Version version) {
+ for (final NormalizedNode<?, ?> c : children) {
+ final ModificationApplyOperation childOp = resolveChildOperation(c.getIdentifier());
+ final ModifiedNode childNode = modification.modifyChild(c.getIdentifier(), childOp, version);
+ childOp.mergeIntoModifiedNode(childNode, c, version);
+ }
+ }
+
+ @Override
+ final void mergeIntoModifiedNode(final ModifiedNode modification, final NormalizedNode<?, ?> value,
+ final Version version) {
+ final Collection<? extends NormalizedNode<?, ?>> children =
+ ((NormalizedNodeContainer<?, ?, ?>)value).getValue();
+
+ switch (modification.getOperation()) {
+ case NONE:
+ // Fresh node, just record a MERGE with a value
+ recursivelyVerifyStructure(value);
+ modification.updateValue(LogicalOperation.MERGE, value);
+ return;
+ case TOUCH:
+
+ mergeChildrenIntoModification(modification, children, version);
+ // We record empty merge value, since real children merges
+ // are already expanded. This is needed to satisfy non-null for merge
+ // original merge value can not be used since it mean different
+ // order of operation - parent changes are always resolved before
+ // children ones, and having node in TOUCH means children was modified
+ // before.
+ modification.updateValue(LogicalOperation.MERGE, support.createEmptyValue(value));
+ return;
+ case MERGE:
+ // Merging into an existing node. Merge data children modifications (maybe recursively) and mark
+ // as MERGE, invalidating cached snapshot
+ mergeChildrenIntoModification(modification, children, version);
+ modification.updateOperationType(LogicalOperation.MERGE);
+ return;
+ case DELETE:
+ // Delete performs a data dependency check on existence of the node. Performing a merge on DELETE means
+ // we are really performing a write. One thing that ruins that are any child modifications. If there
+ // are any, we will perform a read() to get the current state of affairs, turn this into into a WRITE
+ // and then append any child entries.
+ if (!modification.getChildren().isEmpty()) {
+ // Version does not matter here as we'll throw it out
+ final Optional<? extends TreeNode> current = apply(modification, modification.getOriginal(),
+ Version.initial());
+ if (current.isPresent()) {
+ modification.updateValue(LogicalOperation.WRITE, current.get().getData());
+ mergeChildrenIntoModification(modification, children, version);
+ return;
+ }
+ }
+
+ modification.updateValue(LogicalOperation.WRITE, value);
+ return;
+ case WRITE:
+ // We are augmenting a previous write. We'll just walk value's children, get the corresponding
+ // ModifiedNode and run recursively on it
+ mergeChildrenIntoModification(modification, children, version);
+ modification.updateOperationType(LogicalOperation.WRITE);
+ return;
+ default:
+ throw new IllegalArgumentException("Unsupported operation " + modification.getOperation());
+ }
+ }
+