Fix eclipse/checkstyle warnings
[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,
32      * DataTreeCandidateNode) applyRootedNodeToCursor} method that works with rooted node candidates.
33      *
34      * @param cursor cursor from the modification we want to apply the {@code node} to
35      * @param node candidate tree to apply
36      */
37     public static void applyToCursor(final DataTreeModificationCursor cursor, final DataTreeCandidateNode node) {
38         switch (node.getModificationType()) {
39             case DELETE:
40                 cursor.delete(node.getIdentifier());
41                 break;
42             case SUBTREE_MODIFIED:
43                 cursor.enter(node.getIdentifier());
44                 AbstractNodeIterator iterator = new ExitingNodeIterator(null, node.getChildNodes().iterator());
45                 do {
46                     iterator = iterator.next(cursor);
47                 } while (iterator != null);
48                 break;
49             case UNMODIFIED:
50                 // No-op
51                 break;
52             case WRITE:
53                 cursor.write(node.getIdentifier(), node.getDataAfter().get());
54                 break;
55             default:
56                 throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
57         }
58     }
59
60     /**
61      * Applies the {@code node} that is rooted(doesn't have an identifier) in tree A to tree B's {@code cursor}
62      * at location specified by {@code rootPath}.
63      *
64      * @param cursor cursor from the modification we want to apply the {@code node} to
65      * @param rootPath path in the {@code cursor}'s tree we want to apply to candidate to
66      * @param node candidate tree to apply
67      */
68     public static void applyRootedNodeToCursor(final DataTreeModificationCursor cursor,
69             final YangInstanceIdentifier rootPath, final DataTreeCandidateNode node) {
70         switch (node.getModificationType()) {
71             case DELETE:
72                 cursor.delete(rootPath.getLastPathArgument());
73                 break;
74             case SUBTREE_MODIFIED:
75                 cursor.enter(rootPath.getLastPathArgument());
76                 AbstractNodeIterator iterator = new ExitingNodeIterator(null, node.getChildNodes().iterator());
77                 do {
78                     iterator = iterator.next(cursor);
79                 } while (iterator != null);
80                 break;
81             case UNMODIFIED:
82                 // No-op
83                 break;
84             case WRITE:
85                 cursor.write(rootPath.getLastPathArgument(), node.getDataAfter().get());
86                 break;
87             default:
88                 throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
89         }
90     }
91
92     public static void applyRootToCursor(final DataTreeModificationCursor cursor, final DataTreeCandidateNode node) {
93         switch (node.getModificationType()) {
94             case DELETE:
95                 throw new IllegalArgumentException("Can not delete root.");
96             case WRITE:
97             case SUBTREE_MODIFIED:
98                 AbstractNodeIterator iterator = new RootNonExitingIterator(node.getChildNodes().iterator());
99                 do {
100                     iterator = iterator.next(cursor);
101                 } while (iterator != null);
102                 break;
103             case UNMODIFIED:
104                 // No-op
105                 break;
106             default:
107                 throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
108         }
109     }
110
111     private abstract static class AbstractNodeIterator {
112         private final Iterator<DataTreeCandidateNode> iterator;
113
114         AbstractNodeIterator(final Iterator<DataTreeCandidateNode> iterator) {
115             this.iterator = Preconditions.checkNotNull(iterator);
116         }
117
118         AbstractNodeIterator next(final DataTreeModificationCursor cursor) {
119             while (iterator.hasNext()) {
120                 final DataTreeCandidateNode node = iterator.next();
121                 switch (node.getModificationType()) {
122                     case DELETE:
123                         cursor.delete(node.getIdentifier());
124                         break;
125                     case APPEARED:
126                     case DISAPPEARED:
127                     case SUBTREE_MODIFIED:
128                         final Collection<DataTreeCandidateNode> children = node.getChildNodes();
129                         if (!children.isEmpty()) {
130                             cursor.enter(node.getIdentifier());
131                             return new ExitingNodeIterator(this, children.iterator());
132                         }
133                         break;
134                     case UNMODIFIED:
135                         // No-op
136                         break;
137                     case WRITE:
138                         cursor.write(node.getIdentifier(), node.getDataAfter().get());
139                         break;
140                     default:
141                         throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
142                 }
143             }
144             exitNode(cursor);
145             return getParent();
146         }
147
148         protected abstract @Nullable AbstractNodeIterator getParent();
149
150         protected abstract void exitNode(DataTreeModificationCursor cursor);
151     }
152
153     private static final class RootNonExitingIterator extends AbstractNodeIterator {
154
155         protected RootNonExitingIterator(@Nonnull final Iterator<DataTreeCandidateNode> iterator) {
156             super(iterator);
157         }
158
159         @Override
160         protected void exitNode(final DataTreeModificationCursor cursor) {
161             // Intentional noop.
162         }
163
164         @Override
165         protected AbstractNodeIterator getParent() {
166             return null;
167         }
168     }
169
170     private static final class ExitingNodeIterator extends AbstractNodeIterator {
171
172         private final AbstractNodeIterator parent;
173
174         ExitingNodeIterator(@Nullable final AbstractNodeIterator parent,
175                 @Nonnull final Iterator<DataTreeCandidateNode> iterator) {
176             super(iterator);
177             this.parent = parent;
178         }
179
180         @Override
181         protected AbstractNodeIterator getParent() {
182             return parent;
183         }
184
185         @Override
186         protected void exitNode(final DataTreeModificationCursor cursor) {
187             cursor.exit();
188         }
189     }
190 }