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.Date;
13 import java.util.HashSet;
14 import java.util.List;
17 import java.util.TreeMap;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
22 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
25 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
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.SchemaContext;
30 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
32 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
33 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
34 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
38 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
40 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
44 public class GroupingUtils {
46 private GroupingUtils() {
50 * Search given modules for grouping by name defined in uses node.
53 * builder of uses statement
58 * @return grouping with given name if found, null otherwise
60 public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
61 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
62 final int line = usesBuilder.getLine();
63 final String groupingString = usesBuilder.getGroupingPathAsString();
64 String groupingPrefix;
67 if (groupingString.contains(":")) {
68 String[] splitted = groupingString.split(":");
69 if (splitted.length != 2 || groupingString.contains("/")) {
70 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
72 groupingPrefix = splitted[0];
73 groupingName = splitted[1];
75 groupingPrefix = module.getPrefix();
76 groupingName = groupingString;
79 ModuleBuilder dependentModule = null;
80 if (groupingPrefix.equals(module.getPrefix())) {
81 dependentModule = module;
83 dependentModule = ParserUtils.findDependentModuleBuilder(modules, module, groupingPrefix, line);
86 if (dependentModule == null) {
90 GroupingBuilder result = null;
91 Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
92 result = findGroupingBuilder(groupings, groupingName);
97 Builder parent = usesBuilder.getParent();
99 while (parent != null) {
100 if (parent instanceof DataNodeContainerBuilder) {
101 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
102 } else if (parent instanceof RpcDefinitionBuilder) {
103 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
105 result = findGroupingBuilder(groupings, groupingName);
106 if (result == null) {
107 parent = parent.getParent();
113 if (result == null) {
114 throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
121 * Search context for grouping by name defined in uses node.
124 * builder of uses statement
128 * SchemaContext containing already resolved modules
129 * @return grouping with given name if found, null otherwise
131 public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
132 final ModuleBuilder module, final SchemaContext context) {
133 final int line = usesBuilder.getLine();
134 String groupingString = usesBuilder.getGroupingPathAsString();
135 String groupingPrefix;
138 if (groupingString.contains(":")) {
139 String[] splitted = groupingString.split(":");
140 if (splitted.length != 2 || groupingString.contains("/")) {
141 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
143 groupingPrefix = splitted[0];
144 groupingName = splitted[1];
146 groupingPrefix = module.getPrefix();
147 groupingName = groupingString;
150 Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line);
151 return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
155 * Find grouping by name.
158 * collection of grouping builders to search
161 * @return grouping with given name if present in collection, null otherwise
163 public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
164 for (GroupingBuilder grouping : groupings) {
165 if (grouping.getQName().getLocalName().equals(name)) {
173 * Find grouping by name.
176 * collection of grouping definitions to search
179 * @return grouping with given name if present in collection, null otherwise
181 public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
182 for (GroupingDefinition grouping : groupings) {
183 if (grouping.getQName().getLocalName().equals(name)) {
191 * Add nodes defined in uses target grouping to uses parent.
195 public static void updateUsesParent(UsesNodeBuilder usesNode) {
196 DataNodeContainerBuilder parent = usesNode.getParent();
199 for (DataSchemaNodeBuilder child : usesNode.getTargetChildren()) {
200 if (child instanceof GroupingMember) {
201 ((GroupingMember) child).setAddedByUses(true);
203 parent.addChildNode(child);
207 for (GroupingBuilder gb : usesNode.getTargetGroupings()) {
208 gb.setAddedByUses(true);
209 parent.addGrouping(gb);
213 for (TypeDefinitionBuilder tdb : usesNode.getTargetTypedefs()) {
214 tdb.setAddedByUses(true);
215 parent.addTypedef(tdb);
219 for (UnknownSchemaNodeBuilder un : usesNode.getTargetUnknownNodes()) {
220 un.setAddedByUses(true);
221 parent.addUnknownNodeBuilder(un);
226 * Read data defined in target grouping builder, make a copy and add them to
232 public static void collectUsesData(UsesNodeBuilder usesNode) {
233 usesNode.setTargetChildren(collectTargetChildNodes(usesNode));
234 usesNode.setTargetTypedefs(collectTargetTypedefs(usesNode));
235 usesNode.setTargetGroupings(collectTargetGroupings(usesNode));
236 usesNode.setTargetUnknownNodes(collectTargetUnknownNodes(usesNode));
237 usesNode.setDataCollected(true);
241 * Read child nodes defined in target grouping and make a copy of them.
244 * @return copy of child nodes defined in uses target grouping
246 private static Set<DataSchemaNodeBuilder> collectTargetChildNodes(UsesNodeBuilder usesNode) {
247 final GroupingBuilder target = usesNode.getGroupingBuilder();
248 Set<DataSchemaNodeBuilder> childNodes = target.getChildNodeBuilders();
249 Set<DataSchemaNodeBuilder> copies = new HashSet<>();
250 for (DataSchemaNodeBuilder childNode : childNodes) {
251 copies.add(CopyUtils.copy(childNode, usesNode.getParent(), true));
253 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
254 copies.addAll(collectTargetChildNodes(targetUses));
260 * Read typedefs defined in target grouping and make a copy of them.
263 * @return copy of typedefs defined in uses target grouping
265 private static Set<TypeDefinitionBuilder> collectTargetTypedefs(UsesNodeBuilder usesNode) {
266 final GroupingBuilder target = usesNode.getGroupingBuilder();
267 Set<TypeDefinitionBuilder> typedefs = target.getTypeDefinitionBuilders();
268 Set<TypeDefinitionBuilder> copies = new HashSet<>();
269 for (TypeDefinitionBuilder typedef : typedefs) {
270 copies.add(CopyUtils.copy(typedef, usesNode.getParent(), true));
272 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
273 copies.addAll(collectTargetTypedefs(targetUses));
279 * Read groupings defined in target grouping and make a copy of them.
282 * @return copy of groupings defined in uses target grouping
284 private static Set<GroupingBuilder> collectTargetGroupings(UsesNodeBuilder usesNode) {
285 final GroupingBuilder target = usesNode.getGroupingBuilder();
286 Set<GroupingBuilder> groupings = target.getGroupingBuilders();
287 Set<GroupingBuilder> copies = new HashSet<>();
288 for (GroupingBuilder grouping : groupings) {
289 copies.add(CopyUtils.copy(grouping, usesNode.getParent(), true));
291 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
292 copies.addAll(collectTargetGroupings(targetUses));
298 * Read unknown nodes defined in target grouping and make a copy of them.
301 * @return copy of unknown nodes defined in uses target grouping
303 private static List<UnknownSchemaNodeBuilder> collectTargetUnknownNodes(UsesNodeBuilder usesNode) {
304 final GroupingBuilder target = usesNode.getGroupingBuilder();
305 List<UnknownSchemaNodeBuilder> unknownNodes = target.getUnknownNodeBuilders();
306 List<UnknownSchemaNodeBuilder> copies = new ArrayList<>();
307 for (UnknownSchemaNodeBuilder unknownNode : unknownNodes) {
308 copies.add(CopyUtils.copy(unknownNode, usesNode.getParent(), true));
310 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
311 copies.addAll(collectTargetUnknownNodes(targetUses));
317 * Read data defined in target grouping definition, make a copy and add them
318 * to uses node builder.
323 public static void collectUsesDataFromContext(UsesNodeBuilder usesNode) {
324 DataNodeContainerBuilder parent = usesNode.getParent();
325 URI namespace = parent.getQName().getNamespace();
326 Date revision = parent.getQName().getRevision();
327 String prefix = parent.getQName().getPrefix();
328 String moduleName = parent.getModuleName();
329 int line = parent.getLine();
332 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
333 for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
335 DataSchemaNodeBuilder newChild = null;
336 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
337 if (child instanceof AnyXmlSchemaNode) {
338 newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
339 } else if (child instanceof ChoiceNode) {
340 newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, line);
341 } else if (child instanceof ContainerSchemaNode) {
342 newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
343 } else if (child instanceof LeafListSchemaNode) {
344 newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
345 } else if (child instanceof LeafSchemaNode) {
346 newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
347 } else if (child instanceof ListSchemaNode) {
348 newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, line);
351 if (newChild == null) {
352 throw new YangParseException(moduleName, line,
353 "Unknown member of target grouping while resolving uses node.");
355 if (newChild instanceof GroupingMember) {
356 ((GroupingMember) newChild).setAddedByUses(true);
359 newChildren.add(newChild);
362 usesNode.setTargetChildren(newChildren);
365 final Set<GroupingBuilder> newGroupings = new HashSet<>();
366 for (GroupingDefinition g : usesNode.getGroupingDefinition().getGroupings()) {
367 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
368 GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line);
369 newGrouping.setAddedByUses(true);
370 newGroupings.add(newGrouping);
372 usesNode.setTargetGroupings(newGroupings);
375 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
376 for (TypeDefinition<?> td : usesNode.getGroupingDefinition().getTypeDefinitions()) {
377 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
378 TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line);
379 newType.setAddedByUses(true);
380 newTypedefs.add(newType);
382 usesNode.setTargetTypedefs(newTypedefs);
385 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
386 for (UnknownSchemaNode un : usesNode.getGroupingDefinition().getUnknownSchemaNodes()) {
387 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
388 UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line);
389 newNode.setAddedByUses(true);
390 newUnknownNodes.add(newNode);
392 usesNode.setTargetUnknownNodes(newUnknownNodes);
394 usesNode.setDataCollected(true);
398 * Fix schema path of all nodes which were defined by this usesNode.
402 public static void fixUsesNodesPath(UsesNodeBuilder usesNode) {
403 DataNodeContainerBuilder parent = usesNode.getParent();
406 Set<DataSchemaNodeBuilder> currentChildNodes = parent.getChildNodeBuilders();
407 for (DataSchemaNodeBuilder child : currentChildNodes) {
408 if (child instanceof GroupingMember) {
409 GroupingMember gm = (GroupingMember) child;
410 if (gm.isAddedByUses()) {
411 ParserUtils.correctNodePath(child, parent.getPath());
417 Set<GroupingBuilder> currentGroupings = parent.getGroupingBuilders();
418 for (GroupingBuilder child : currentGroupings) {
419 if (child.isAddedByUses()) {
420 ParserUtils.correctNodePath(child, parent.getPath());
426 Set<TypeDefinitionBuilder> currentTypedefs = parent.getTypeDefinitionBuilders();
427 for (TypeDefinitionBuilder child : currentTypedefs) {
428 if (child.isAddedByUses()) {
429 ParserUtils.correctNodePath(child, parent.getPath());
435 List<UnknownSchemaNodeBuilder> currentUN = parent.getUnknownNodeBuilders();
436 for (UnknownSchemaNodeBuilder un : currentUN) {
437 if (un.isAddedByUses()) {
438 ParserUtils.correctNodePath(un, parent.getPath());
444 * Perform refinement of uses target grouping nodes. Uses process has to be
449 public static void performRefine(UsesNodeBuilder usesNode) {
450 for (RefineHolder refine : usesNode.getRefines()) {
451 DataSchemaNodeBuilder nodeToRefine = null;
452 for (DataSchemaNodeBuilder dataNode : usesNode.getParent().getChildNodeBuilders()) {
453 if (refine.getName().equals(dataNode.getQName().getLocalName())) {
454 nodeToRefine = dataNode;
458 if (nodeToRefine == null) {
459 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
460 + refine.getName() + "' not found");
462 RefineUtils.performRefine(nodeToRefine, refine);
463 usesNode.addRefineNode(nodeToRefine);