Deprecate DataNodeIterator
[yangtools.git] / yang / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / util / SchemaNodeUtils.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.model.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.Optional;
17 import java.util.Set;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
28 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.Module;
30 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
31 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
32 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
34
35 public final class SchemaNodeUtils {
36     private SchemaNodeUtils() {
37         // Hidden on purpose
38     }
39
40     public static Optional<SchemaNode> getOriginalIfPossible(final SchemaNode node) {
41         if (node instanceof DerivableSchemaNode) {
42             @SuppressWarnings("unchecked")
43             final Optional<SchemaNode> ret  = (Optional<SchemaNode>) ((DerivableSchemaNode) node).getOriginal();
44             return ret;
45         }
46         return Optional.empty();
47     }
48
49     public static SchemaNode getRootOriginalIfPossible(final SchemaNode data) {
50         Optional<SchemaNode> previous = Optional.empty();
51         Optional<SchemaNode> next = getOriginalIfPossible(data);
52         while (next.isPresent()) {
53             previous = next;
54             next = getOriginalIfPossible(next.get());
55         }
56         return previous.orElse(null);
57     }
58
59     /**
60      * Returns RPC input or output schema based on supplied QName.
61      *
62      * @param rpc RPC Definition
63      * @param qname input or output QName with namespace same as RPC
64      * @return input or output schema. Returns null if RPC does not have input/output specified.
65      */
66     public static @Nullable ContainerSchemaNode getRpcDataSchema(final @NonNull RpcDefinition rpc,
67             final @NonNull QName qname) {
68         requireNonNull(rpc, "Rpc Schema must not be null");
69         switch (requireNonNull(qname, "QName must not be null").getLocalName()) {
70             case "input":
71                 return rpc.getInput();
72             case "output":
73                 return rpc.getOutput();
74             default:
75                 throw new IllegalArgumentException("Supplied qname " + qname
76                         + " does not represent rpc input or output.");
77         }
78     }
79
80     @Beta
81     public static @NonNull Collection<? extends TypeDefinition<?>> getAllTypeDefinitions(
82             final DataNodeContainer parent) {
83         final List<TypeDefinition<?>> typedefs = new ArrayList<>();
84         traverse(new DataNodeAggregator() {
85             @Override
86             protected void addTypedefs(final Collection<? extends TypeDefinition<?>> typeDefs) {
87                 typedefs.addAll(typeDefs);
88             }
89         }, requireNonNull(parent));
90         return typedefs;
91     }
92
93     @Beta
94     public static @NonNull Collection<? extends ContainerSchemaNode> getAllContainers(final DataNodeContainer parent) {
95         final List<ContainerSchemaNode> containers = new ArrayList<>();
96         traverse(new DataNodeAggregator() {
97             @Override
98             protected void addContainer(final ContainerSchemaNode containerNode) {
99                 containers.add(containerNode);
100             }
101         }, requireNonNull(parent));
102         return containers;
103     }
104
105     @Beta
106     public static void traverse(final @NonNull DataNodeAggregator aggregator, final DataNodeContainer dataNode) {
107         if (dataNode == null) {
108             return;
109         }
110
111         final Iterable<DataSchemaNode> childNodes = dataNode.getChildNodes();
112         if (childNodes != null) {
113             for (DataSchemaNode childNode : childNodes) {
114                 if (childNode.isAugmenting()) {
115                     continue;
116                 }
117                 aggregator.addChild(childNode);
118                 if (childNode instanceof ContainerSchemaNode) {
119                     final ContainerSchemaNode containerNode = (ContainerSchemaNode) childNode;
120                     aggregator.addContainer(containerNode);
121                     traverse(aggregator, containerNode);
122                 } else if (childNode instanceof ListSchemaNode) {
123                     final ListSchemaNode list = (ListSchemaNode) childNode;
124                     aggregator.addList(list);
125                     traverse(aggregator, list);
126                 } else if (childNode instanceof ChoiceSchemaNode) {
127                     final ChoiceSchemaNode choiceNode = (ChoiceSchemaNode) childNode;
128                     aggregator.addChoice(choiceNode);
129                     for (final CaseSchemaNode caseNode : choiceNode.getCases().values()) {
130                         traverse(aggregator, caseNode);
131                     }
132                 }
133             }
134         }
135
136         aggregator.addTypedefs(dataNode.getTypeDefinitions());
137
138         traverseModule(aggregator, dataNode);
139         traverseGroupings(aggregator, dataNode);
140     }
141
142     private static void traverseModule(final DataNodeAggregator aggregator, final DataNodeContainer dataNode) {
143         final Module module;
144         if (dataNode instanceof Module) {
145             module = (Module) dataNode;
146         } else {
147             return;
148         }
149
150         for (NotificationDefinition notificationDefinition : module.getNotifications()) {
151             traverse(aggregator, notificationDefinition);
152         }
153
154         for (RpcDefinition rpcDefinition : module.getRpcs()) {
155             aggregator.addTypedefs(rpcDefinition.getTypeDefinitions());
156             ContainerSchemaNode input = rpcDefinition.getInput();
157             if (input != null) {
158                 traverse(aggregator, input);
159             }
160             ContainerSchemaNode output = rpcDefinition.getOutput();
161             if (output != null) {
162                 traverse(aggregator, output);
163             }
164         }
165     }
166
167     private static void traverseGroupings(final DataNodeAggregator aggregator, final DataNodeContainer dataNode) {
168         final Set<GroupingDefinition> groupings = dataNode.getGroupings();
169         if (groupings != null) {
170             for (GroupingDefinition grouping : groupings) {
171                 aggregator.addGrouping(grouping);
172                 traverse(aggregator, grouping);
173             }
174         }
175     }
176 }