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