+ 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, 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<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;
+ }
+
+ throw new IllegalArgumentException("Unsupported operation " + modification.getOperation());
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private NormalizedNode<?, ?> createEmptyValue(NormalizedNode<?, ?> value,
+ Collection<NormalizedNode<?, ?>> children) {
+ NormalizedNodeContainerBuilder builder = createBuilder(value);
+ for (NormalizedNode<?, ?> child : children) {
+ builder.removeChild(child.getIdentifier());
+ }
+ return builder.build();
+ }
+
+ @Override
+ protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta, final Version version) {