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