BUG-1382: eliminate use of QName.getPrefix from yang parser
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / GroupingUtils.java
1 /*
2  * Copyright (c) 2013 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.parser.builder.impl;
9
10 import com.google.common.base.Splitter;
11 import java.net.URI;
12 import java.util.Comparator;
13 import java.util.Date;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.TreeMap;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
19 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
20 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
21 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
22 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
23 import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
24 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
25 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
26
27 public final class GroupingUtils {
28     private static final Splitter SLASH_SPLITTER = Splitter.on('/');
29
30     private GroupingUtils() {
31     }
32
33     /**
34      * Search given modules for grouping by name defined in uses node.
35      *
36      * @param usesBuilder
37      *            builder of uses statement
38      * @param modules
39      *            all loaded modules
40      * @param module
41      *            current module
42      * @return grouping with given name if found, null otherwise
43      */
44     public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
45             final Map<URI, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
46         final int line = usesBuilder.getLine();
47
48         SchemaPath groupingPath = usesBuilder.getTargetGroupingPath();
49         QName groupingName = groupingPath.getPathFromRoot().iterator().next();
50         ModuleBuilder dependentModule = BuilderUtils.findModule(groupingName, modules);
51
52         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
53         GroupingBuilder result = findGroupingBuilder(groupings, groupingName.getLocalName());
54         if (result != null) {
55             return result;
56         }
57
58         Builder parent = usesBuilder.getParent();
59         while (parent != null) {
60             if (parent instanceof DataNodeContainerBuilder) {
61                 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
62             } else if (parent instanceof RpcDefinitionBuilder) {
63                 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
64             }
65             result = findGroupingBuilder(groupings, groupingName.getLocalName());
66             if (result == null) {
67                 parent = parent.getParent();
68             } else {
69                 break;
70             }
71         }
72
73         if (result == null) {
74             throw new YangParseException(module.getName(), line, "Grouping '" + groupingName + "' not found.");
75         }
76         return result;
77     }
78
79     /**
80      * Find grouping by name.
81      *
82      * @param groupings
83      *            collection of grouping builders to search
84      * @param name
85      *            name of grouping
86      * @return grouping with given name if present in collection, null otherwise
87      */
88     private static GroupingBuilder findGroupingBuilder(final Set<GroupingBuilder> groupings, final String name) {
89         for (GroupingBuilder grouping : groupings) {
90             if (grouping.getQName().getLocalName().equals(name)) {
91                 return grouping;
92             }
93         }
94         return null;
95     }
96
97     /**
98      * Perform refinement of uses target grouping nodes. Uses process has to be
99      * already performed.
100      *
101      * @param usesNode
102      *            uses node containing refine statements
103      */
104     public static void performRefine(final UsesNodeBuilder usesNode) {
105         for (RefineBuilder refine : usesNode.getRefines()) {
106             String refineTargetPath = refine.getTargetPathString();
107
108             Builder currentNode = usesNode.getParent();
109             for (String pathElement : SLASH_SPLITTER.split(refineTargetPath)) {
110                 if (currentNode instanceof DataNodeContainerBuilder) {
111                     currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
112                 } else if (currentNode instanceof ChoiceBuilder) {
113                     currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
114                 }
115             }
116
117             DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
118             if (nodeToRefine == null) {
119                 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
120                         + refine.getTargetPathString() + "' not found");
121             }
122             RefineUtils.performRefine(nodeToRefine, refine);
123             usesNode.addRefineNode(nodeToRefine);
124         }
125     }
126
127     public static class UsesComparator implements Comparator<UsesNodeBuilder> {
128         @Override
129         public int compare(final UsesNodeBuilder o1, final UsesNodeBuilder o2) {
130             return getElementPosition(o2) - getElementPosition(o1);
131         }
132     }
133
134     private static int getElementPosition(final UsesNodeBuilder usesNode) {
135         int i = 0;
136         Builder parent = usesNode.getParent();
137         while (!(parent instanceof ModuleBuilder)) {
138             parent = parent.getParent();
139             i++;
140         }
141         return i;
142     }
143
144 }