BUG-4295: instantiate MERGE operations lazily
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / OperationWithModification.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
14 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
15 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
16 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
17
18 final class OperationWithModification {
19     private static final Function<TreeNode, NormalizedNode<?, ?>> READ_DATA = new Function<TreeNode, NormalizedNode<?, ?>>() {
20         @Override
21         public NormalizedNode<?, ?> apply(final TreeNode input) {
22             return input.getData();
23         }
24     };
25
26     private final ModifiedNode modification;
27     private final ModificationApplyOperation applyOperation;
28
29     private OperationWithModification(final ModificationApplyOperation op, final ModifiedNode mod) {
30         this.modification = Preconditions.checkNotNull(mod);
31         this.applyOperation = Preconditions.checkNotNull(op);
32     }
33
34     void write(final NormalizedNode<?, ?> value) {
35         modification.write(value);
36         /**
37          * Fast validation of structure, full validation on written data will be run during seal.
38          */
39         applyOperation.verifyStructure(value, false);
40     }
41
42     void merge(final NormalizedNode<?, ?> data, final Version version) {
43         /*
44          * A merge operation will end up overwriting parts of the tree, retaining others. We want to
45          * make sure we do not validate the complete resulting structure, but rather just what was
46          * written. In order to do that, we first pretend the data was written, run verification and
47          * then perform the merge -- with the explicit assumption that adding the newly-validated
48          * data with the previously-validated data will not result in invalid data.
49          */
50         applyOperation.verifyStructure(data, true);
51         applyOperation.mergeIntoModifiedNode(modification, data, version);
52     }
53
54     void delete() {
55         modification.delete();
56     }
57
58     /**
59      * Read a particular child. If the child has been modified and does not have a stable
60      * view, one will we instantiated with specified version.
61      *
62      * @param child
63      * @param version
64      * @return
65      */
66     Optional<NormalizedNode<?, ?>> read(final PathArgument child, final Version version) {
67         final Optional<ModifiedNode> maybeChild = modification.getChild(child);
68         if (maybeChild.isPresent()) {
69             final ModifiedNode childNode = maybeChild.get();
70
71             Optional<TreeNode> snapshot = childNode.getSnapshot();
72             if (snapshot == null) {
73                 // Snapshot is not present, force instantiation
74                 snapshot = applyOperation.getChild(child).get().apply(childNode, childNode.getOriginal(), version);
75             }
76
77             return snapshot.transform(READ_DATA);
78         }
79
80         Optional<TreeNode> snapshot = modification.getSnapshot();
81         if (snapshot == null) {
82             snapshot = apply(modification.getOriginal(), version);
83         }
84
85         if (snapshot.isPresent()) {
86             return snapshot.get().getChild(child).transform(READ_DATA);
87         }
88
89         return Optional.absent();
90     }
91
92     public ModifiedNode getModification() {
93         return modification;
94     }
95
96     public ModificationApplyOperation getApplyOperation() {
97         return applyOperation;
98     }
99
100     public Optional<TreeNode> apply(final Optional<TreeNode> data, final Version version) {
101         return applyOperation.apply(modification, data, version);
102     }
103
104     public static OperationWithModification from(final ModificationApplyOperation operation,
105             final ModifiedNode modification) {
106         return new OperationWithModification(operation, modification);
107     }
108 }