d36a4816a598580348fcfad18e9029ed83b5761d
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / schema / tree / DataTreeCandidateNodes.java
1 /*
2  * Copyright (c) 2015 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.api.schema.tree;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import java.util.Collection;
13 import java.util.Iterator;
14 import javax.annotation.Nonnull;
15 import javax.annotation.Nullable;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
18
19 @Beta
20 public final class DataTreeCandidateNodes {
21     private DataTreeCandidateNodes() {
22         throw new UnsupportedOperationException();
23     }
24
25     public static DataTreeCandidateNode fromNormalizedNode(final NormalizedNode<?, ?> node) {
26         return new NormalizedNodeDataTreeCandidateNode(node);
27     }
28
29     /**
30      * Applies the {@code node} to the {@code cursor}, note that if the top node of (@code node} is RootNode
31      * you need to use {@link #applyRootedNodeToCursor(DataTreeModificationCursor, YangInstanceIdentifier, DataTreeCandidateNode) applyRootedNodeToCursor}
32      * method that works with rooted node candidates
33      * @param cursor cursor from the modification we want to apply the {@code node} to
34      * @param node candidate tree to apply
35      */
36     public static void applyToCursor(final DataTreeModificationCursor cursor, final DataTreeCandidateNode node) {
37         switch (node.getModificationType()) {
38         case DELETE:
39             cursor.delete(node.getIdentifier());
40             break;
41         case SUBTREE_MODIFIED:
42                 cursor.enter(node.getIdentifier());
43                 AbstractNodeIterator iterator = new ExitingNodeIterator(null, node.getChildNodes().iterator());
44             do {
45                 iterator = iterator.next(cursor);
46             } while (iterator != null);
47             break;
48         case UNMODIFIED:
49             // No-op
50             break;
51         case WRITE:
52             cursor.write(node.getIdentifier(), node.getDataAfter().get());
53             break;
54         default:
55             throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
56         }
57     }
58
59     /**
60      * Applies the {@code node} that is rooted(doesn't have an identifier) in tree A to tree B's {@code cursor}
61      * at location specified by {@code rootPath}
62      * @param cursor cursor from the modification we want to apply the {@code node} to
63      * @param rootPath path in the {@code cursor}'s tree we want to apply to candidate to
64      * @param node candidate tree to apply
65      */
66     public static void applyRootedNodeToCursor(final DataTreeModificationCursor cursor, final YangInstanceIdentifier rootPath, final DataTreeCandidateNode node) {
67         switch (node.getModificationType()) {
68             case DELETE:
69                 cursor.delete(rootPath.getLastPathArgument());
70                 break;
71             case SUBTREE_MODIFIED:
72                 cursor.enter(rootPath.getLastPathArgument());
73                 AbstractNodeIterator iterator = new ExitingNodeIterator(null, node.getChildNodes().iterator());
74                 do {
75                     iterator = iterator.next(cursor);
76                 } while (iterator != null);
77                 break;
78             case UNMODIFIED:
79                 // No-op
80                 break;
81             case WRITE:
82                 cursor.write(rootPath.getLastPathArgument(), node.getDataAfter().get());
83                 break;
84             default:
85                 throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
86         }
87     }
88
89     public static void applyRootToCursor(final DataTreeModificationCursor cursor, final DataTreeCandidateNode node) {
90         switch (node.getModificationType()) {
91             case DELETE:
92                 throw new IllegalArgumentException("Can not delete root.");
93             case WRITE:
94             case SUBTREE_MODIFIED:
95                 AbstractNodeIterator iterator = new RootNonExitingIterator(node.getChildNodes().iterator());
96                 do {
97                     iterator = iterator.next(cursor);
98                 } while (iterator != null);
99                 break;
100             case UNMODIFIED:
101                 // No-op
102                 break;
103             default:
104                 throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
105         }
106     }
107
108     private abstract static class AbstractNodeIterator {
109         private final Iterator<DataTreeCandidateNode> iterator;
110
111         AbstractNodeIterator(final Iterator<DataTreeCandidateNode> iterator) {
112             this.iterator = Preconditions.checkNotNull(iterator);
113         }
114
115         AbstractNodeIterator next(final DataTreeModificationCursor cursor) {
116             while (iterator.hasNext()) {
117                 final DataTreeCandidateNode node = iterator.next();
118                 switch (node.getModificationType()) {
119                 case DELETE:
120                     cursor.delete(node.getIdentifier());
121                     break;
122                 case APPEARED:
123                 case DISAPPEARED:
124                 case SUBTREE_MODIFIED:
125                     final Collection<DataTreeCandidateNode> children = node.getChildNodes();
126                     if (!children.isEmpty()) {
127                         cursor.enter(node.getIdentifier());
128                             return new ExitingNodeIterator(this, children.iterator());
129                     }
130                     break;
131                 case UNMODIFIED:
132                     // No-op
133                     break;
134                 case WRITE:
135                     cursor.write(node.getIdentifier(), node.getDataAfter().get());
136                     break;
137                 default:
138                     throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
139                 }
140             }
141             exitNode(cursor);
142             return getParent();
143         }
144
145         protected abstract @Nullable AbstractNodeIterator getParent();
146
147         protected abstract void exitNode(DataTreeModificationCursor cursor);
148     }
149
150     private static final class RootNonExitingIterator extends AbstractNodeIterator {
151
152         protected RootNonExitingIterator(@Nonnull final Iterator<DataTreeCandidateNode> iterator) {
153             super(iterator);
154         }
155
156         @Override
157         protected void exitNode(final DataTreeModificationCursor cursor) {
158             // Intentional noop.
159         }
160
161         @Override
162         protected AbstractNodeIterator getParent() {
163             return null;
164         }
165     }
166
167     private static final class ExitingNodeIterator extends AbstractNodeIterator {
168
169         private final AbstractNodeIterator parent;
170
171         public ExitingNodeIterator(@Nullable final AbstractNodeIterator parent,
172                 @Nonnull final Iterator<DataTreeCandidateNode> iterator) {
173             super(iterator);
174             this.parent = parent;
175         }
176
177         @Override
178         protected AbstractNodeIterator getParent() {
179             return parent;
180         }
181
182         @Override
183         protected void exitNode(final DataTreeModificationCursor cursor) {
184             cursor.exit();
185         }
186     }
187 }