2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.util;
11 import java.util.ArrayList;
12 import java.util.Comparator;
13 import java.util.Date;
14 import java.util.HashSet;
15 import java.util.List;
18 import java.util.TreeMap;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
23 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
26 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
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.SchemaContext;
31 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
33 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
34 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
39 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
40 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
46 public final class GroupingUtils {
48 private GroupingUtils() {
52 * Search given modules for grouping by name defined in uses node.
55 * builder of uses statement
60 * @return grouping with given name if found, null otherwise
62 public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
63 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
64 final int line = usesBuilder.getLine();
66 final String groupingString = usesBuilder.getGroupingPathAsString();
67 String groupingPrefix;
70 if (groupingString.contains(":")) {
71 String[] splitted = groupingString.split(":");
72 if (splitted.length != 2 || groupingString.contains("/")) {
73 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
75 groupingPrefix = splitted[0];
76 groupingName = splitted[1];
78 groupingPrefix = module.getPrefix();
79 groupingName = groupingString;
82 ModuleBuilder dependentModule;
83 if (groupingPrefix.equals(module.getPrefix())) {
84 dependentModule = module;
86 dependentModule = ParserUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
89 if (dependentModule == null) {
93 GroupingBuilder result;
94 Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
95 result = findGroupingBuilder(groupings, groupingName);
100 Builder parent = usesBuilder.getParent();
102 while (parent != null) {
103 if (parent instanceof DataNodeContainerBuilder) {
104 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
105 } else if (parent instanceof RpcDefinitionBuilder) {
106 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
108 result = findGroupingBuilder(groupings, groupingName);
109 if (result == null) {
110 parent = parent.getParent();
116 if (result == null) {
117 throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
124 * Search context for grouping by name defined in uses node.
127 * builder of uses statement
131 * SchemaContext containing already resolved modules
132 * @return grouping with given name if found, null otherwise
134 public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
135 final ModuleBuilder module, final SchemaContext context) {
136 final int line = usesBuilder.getLine();
137 String groupingString = usesBuilder.getGroupingPathAsString();
138 String groupingPrefix;
141 if (groupingString.contains(":")) {
142 String[] splitted = groupingString.split(":");
143 if (splitted.length != 2 || groupingString.contains("/")) {
144 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
146 groupingPrefix = splitted[0];
147 groupingName = splitted[1];
149 groupingPrefix = module.getPrefix();
150 groupingName = groupingString;
153 Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line);
154 return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
158 * Find grouping by name.
161 * collection of grouping builders to search
164 * @return grouping with given name if present in collection, null otherwise
166 public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
167 for (GroupingBuilder grouping : groupings) {
168 if (grouping.getQName().getLocalName().equals(name)) {
176 * Find grouping by name.
179 * collection of grouping definitions to search
182 * @return grouping with given name if present in collection, null otherwise
184 public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
185 for (GroupingDefinition grouping : groupings) {
186 if (grouping.getQName().getLocalName().equals(name)) {
194 * Read data defined in target grouping definition, make a copy and add them
195 * to uses node builder.
198 * used node builder to which are copied nodes from its
199 * <code>GroupingDefinition</code>
201 * URI with parent namespace
203 * date with parent revision date
205 * string with parent prefix
207 * string with parent module name
209 * line from YANG file where parent node is defined
211 public static Set<DataSchemaNodeBuilder> getTargetGroupingDefinitionNodesWithNewNamespace(
212 final UsesNodeBuilder usesNode, final URI namespace, final Date revision, final String prefix,
213 final String moduleName, final int line) {
214 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
215 for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
217 DataSchemaNodeBuilder newChild = null;
218 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
219 if (child instanceof AnyXmlSchemaNode) {
220 newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
221 } else if (child instanceof ChoiceNode) {
222 newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, line);
223 } else if (child instanceof ContainerSchemaNode) {
224 newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
225 } else if (child instanceof LeafListSchemaNode) {
226 newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
227 } else if (child instanceof LeafSchemaNode) {
228 newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
229 } else if (child instanceof ListSchemaNode) {
230 newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, line);
233 if (newChild == null) {
234 throw new YangParseException(moduleName, line,
235 "Unknown member of target grouping while resolving uses node.");
238 ((GroupingMember) newChild).setAddedByUses(true);
239 newChildren.add(newChild);
245 public static Set<TypeDefinitionBuilder> getTargetGroupingDefinitionTypedefsWithNewNamespace(
246 UsesNodeBuilder usesNode, URI namespace, Date revision, String prefix, String moduleName, int line) {
247 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
248 for (TypeDefinition<?> td : usesNode.getGroupingDefinition().getTypeDefinitions()) {
249 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
250 TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line);
251 newType.setAddedByUses(true);
252 newTypedefs.add(newType);
257 public static Set<GroupingBuilder> getTargetGroupingDefinitionGroupingsWithNewNamespace(UsesNodeBuilder usesNode,
258 URI namespace, Date revision, String prefix, String moduleName, int line) {
259 final Set<GroupingBuilder> newGroupings = new HashSet<>();
260 for (GroupingDefinition g : usesNode.getGroupingDefinition().getGroupings()) {
261 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
262 GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line);
263 newGrouping.setAddedByUses(true);
264 newGroupings.add(newGrouping);
269 public static List<UnknownSchemaNodeBuilder> getTargetGroupingDefinitionUnknownNodesWithNewNamespace(
270 UsesNodeBuilder usesNode, URI namespace, Date revision, String prefix, String moduleName, int line) {
271 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
272 for (UnknownSchemaNode un : usesNode.getGroupingDefinition().getUnknownSchemaNodes()) {
273 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
274 UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line);
275 newNode.setAddedByUses(true);
276 newUnknownNodes.add(newNode);
278 return newUnknownNodes;
282 * Perform refinement of uses target grouping nodes. Uses process has to be
286 * uses node containing refine statements
288 public static void performRefine(UsesNodeBuilder usesNode) {
289 for (RefineHolder refine : usesNode.getRefines()) {
290 String refineTargetPath = refine.getName();
292 String[] splitted = refineTargetPath.split("/");
293 Builder currentNode = usesNode.getParent();
294 for (String pathElement : splitted) {
295 if (currentNode instanceof DataNodeContainerBuilder) {
296 currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
297 } else if (currentNode instanceof ChoiceBuilder) {
298 currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
302 DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
303 if (nodeToRefine == null) {
304 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
305 + refine.getName() + "' not found");
307 RefineUtils.performRefine(nodeToRefine, refine);
308 usesNode.addRefineNode(nodeToRefine);
312 public static class UsesComparator implements Comparator<UsesNodeBuilder> {
314 public int compare(UsesNodeBuilder o1, UsesNodeBuilder o2) {
315 return getElementPosition(o2) - getElementPosition(o1);
319 private static int getElementPosition(UsesNodeBuilder usesNode) {
321 Builder parent = usesNode.getParent();
322 while (!(parent instanceof ModuleBuilder)) {
323 parent = parent.getParent();