Merge "BUG-1275: teach NormalizedNode builders about size hints"
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / RootModificationApplyOperation.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.Optional;
11
12 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
13 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
14 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
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 /**
19  * Represents a {@link ModificationApplyOperation} which is rooted at conceptual
20  * top of data tree.
21  *
22  * <p>
23  * This implementation differs from other implementations in this package that
24  * is not immutable, but may be upgraded to newer state if available by
25  * explicitly invoking {@link #upgradeIfPossible()} and also serves as factory
26  * for deriving snapshot {@link RootModificationApplyOperation} which will not
27  * be affected by upgrade of original one.
28  *
29  * <p>
30  * There are two variations of this {@link ModificationApplyOperation}:
31  * <ul>
32  * <li>
33  * <b>Upgradable</b> - operation may be upgraded to different backing
34  * implementation by invoking {@link #upgradeIfPossible()}.</li>
35  * <li><b>Not Upgradable</b> - operation is immutable, invocation of
36  * {@link #upgradeIfPossible()} is no-op and method {@link #snapshot()} returns
37  * pointer on same object.
38  *
39  * <h3>Upgradable Root Modification Operation</h3>
40  *
41  * Upgradable Root Modification Operation may be created using:
42  * <ul>
43  * <li> {@link #from(ModificationApplyOperation)} with other upgradable root
44  * modification as an argument
45  * <li>using factory {@link LatestOperationHolder} which instantiates Upgradable
46  * Root Modification Operations and provides an option to set latest
47  * implementation.
48  * </ul>
49  * <p>
50  * Upgradable root operation is never upgraded to latest operation
51  * automatically, but client code must explicitly invoke
52  * {@link #upgradeIfPossible()} to get latest implementation.
53  *
54  * Note: This is helpful for implementing
55  * {@link org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification}
56  * which may be derived from
57  * {@link org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree} before
58  * update of schema and user actually writes data after schema update. During
59  * update user did not invoked any operation.
60  *
61  */
62 abstract class RootModificationApplyOperation implements ModificationApplyOperation {
63
64     @Override
65     public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
66         return getDelegate().getChild(child);
67     }
68
69     @Override
70     public final void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current)
71             throws DataValidationFailedException {
72         getDelegate().checkApplicable(path, modification, current);
73     }
74
75     @Override
76     public final Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> currentMeta,
77             final Version version) {
78         return getDelegate().apply(modification, currentMeta, version);
79     }
80
81     @Override
82     public boolean equals(final Object obj) {
83         return getDelegate().equals(obj);
84     }
85
86     @Override
87     public int hashCode() {
88         return getDelegate().hashCode();
89     }
90
91     @Override
92     public String toString() {
93         return getDelegate().toString();
94     }
95
96     @Override
97     public void verifyStructure(final ModifiedNode modification) throws IllegalArgumentException {
98         getDelegate().verifyStructure(modification);
99     }
100
101     /**
102      * Return the underlying delegate.
103      *
104      * @return Underlying delegate.
105      */
106     abstract ModificationApplyOperation getDelegate();
107
108     /**
109      * Creates a snapshot from this modification, which may have separate
110      * upgrade lifecycle and is not affected by upgrades
111      * <p>
112      * Newly created snapshot uses backing implementation of this modi
113      *
114      * @return Derived {@link RootModificationApplyOperation} with separate
115      *         upgrade lifecycle.
116      */
117     public abstract RootModificationApplyOperation snapshot();
118
119     /**
120      * Upgrades backing implementation to latest available, if possible.
121      * <p>
122      * Latest implementation of {@link RootModificationApplyOperation} is
123      * managed by {@link LatestOperationHolder} which was used to construct this
124      * operation and latest operation is updated by
125      * {@link LatestOperationHolder#setCurrent(ModificationApplyOperation)}.
126      */
127     public abstract void upgradeIfPossible();
128
129     public static RootModificationApplyOperation from(final ModificationApplyOperation resolver) {
130         if (resolver instanceof RootModificationApplyOperation) {
131             return ((RootModificationApplyOperation) resolver).snapshot();
132         }
133         return new NotUpgradable(resolver);
134     }
135
136     /**
137      * Implementation of Upgradable {@link RootModificationApplyOperation}
138      *
139      * This implementation is associated with {@link LatestOperationHolder}
140      * which holds latest available implementation, which may be used for
141      * upgrade.
142      *
143      * Upgrading {@link LatestOperationHolder} will not affect any instance,
144      * unless client invoked {@link #upgradeIfPossible()} which will result in
145      * changing delegate to the latest one.
146      *
147      */
148     private static final class Upgradable extends RootModificationApplyOperation {
149
150         private final LatestOperationHolder holder;
151         private ModificationApplyOperation delegate;
152
153         public Upgradable(final LatestOperationHolder holder, final ModificationApplyOperation delegate) {
154             this.holder = holder;
155             this.delegate = delegate;
156
157         }
158
159         @Override
160         public void upgradeIfPossible() {
161             ModificationApplyOperation holderCurrent = holder.getCurrent();
162             if (holderCurrent != delegate) {
163                 // FIXME: Allow update only if there is addition of models, not
164                 // removals.
165                 delegate = holderCurrent;
166             }
167
168         }
169
170         @Override
171         ModificationApplyOperation getDelegate() {
172             return delegate;
173         }
174
175         @Override
176         public RootModificationApplyOperation snapshot() {
177             return new Upgradable(holder, getDelegate());
178         }
179
180     }
181
182     private static final class NotUpgradable extends RootModificationApplyOperation {
183
184         private final ModificationApplyOperation delegate;
185
186         public NotUpgradable(final ModificationApplyOperation delegate) {
187             this.delegate = delegate;
188         }
189
190         @Override
191         public ModificationApplyOperation getDelegate() {
192             return delegate;
193         }
194
195         @Override
196         public void upgradeIfPossible() {
197             // Intentional noop
198         }
199
200         @Override
201         public RootModificationApplyOperation snapshot() {
202             return this;
203         }
204     }
205
206     /**
207      * Holder and factory for upgradable root modifications
208      *
209      * This class is factory for upgradable root modifications and provides an
210      * access to set latest backing implementation.
211      *
212      */
213     static class LatestOperationHolder {
214
215         private ModificationApplyOperation current = new AlwaysFailOperation();
216
217         /**
218          * Return latest backing implemenation
219          *
220          * @return
221          */
222         public ModificationApplyOperation getCurrent() {
223             return current;
224         }
225
226         /**
227          * Sets latest backing implementation of associated
228          * {@link RootModificationApplyOperation}.
229          * <p>
230          * Note: This does not result in upgrading implementation of already
231          * existing {@link RootModificationApplyOperation}. Users, which
232          * obtained instances using {@link #newSnapshot()}, deriving
233          * {@link RootModificationApplyOperation} from this modification must
234          * explicitly invoke
235          * {@link RootModificationApplyOperation#upgradeIfPossible()} on their
236          * instance to be updated to latest backing implementation.
237          *
238          * @param newApplyOper
239          *            New backing implementation
240          */
241         public void setCurrent(final ModificationApplyOperation newApplyOper) {
242             current = newApplyOper;
243         }
244
245         /**
246          *
247          * Creates new upgradable {@link RootModificationApplyOperation}
248          * associated with holder.
249          *
250          * @return New upgradable {@link RootModificationApplyOperation} with
251          *         {@link #getCurrent()} used as backing implementation.
252          */
253         public RootModificationApplyOperation newSnapshot() {
254             return new Upgradable(this, current);
255         }
256
257     }
258 }