Yang parser refactoring.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / 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.util;
9
10 import java.util.Comparator;
11 import java.util.Date;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.TreeMap;
15
16 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
17 import org.opendaylight.yangtools.yang.model.api.Module;
18 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
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.UsesNodeBuilder;
24 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
25 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
27
28 public final class GroupingUtils {
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<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
46         final int line = usesBuilder.getLine();
47
48         final String groupingString = usesBuilder.getGroupingPathAsString();
49         String groupingPrefix;
50         String groupingName;
51
52         if (groupingString.contains(":")) {
53             String[] splitted = groupingString.split(":");
54             if (splitted.length != 2 || groupingString.contains("/")) {
55                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
56             }
57             groupingPrefix = splitted[0];
58             groupingName = splitted[1];
59         } else {
60             groupingPrefix = module.getPrefix();
61             groupingName = groupingString;
62         }
63
64         ModuleBuilder dependentModule;
65         if (groupingPrefix.equals(module.getPrefix())) {
66             dependentModule = module;
67         } else {
68             dependentModule = ParserUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
69         }
70
71         if (dependentModule == null) {
72             return null;
73         }
74
75         GroupingBuilder result;
76         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
77         result = findGroupingBuilder(groupings, groupingName);
78         if (result != null) {
79             return result;
80         }
81
82         Builder parent = usesBuilder.getParent();
83
84         while (parent != null) {
85             if (parent instanceof DataNodeContainerBuilder) {
86                 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
87             } else if (parent instanceof RpcDefinitionBuilder) {
88                 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
89             }
90             result = findGroupingBuilder(groupings, groupingName);
91             if (result == null) {
92                 parent = parent.getParent();
93             } else {
94                 break;
95             }
96         }
97
98         if (result == null) {
99             throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
100                     + "' not found.");
101         }
102         return result;
103     }
104
105     /**
106      * Search context for grouping by name defined in uses node.
107      *
108      * @param usesBuilder
109      *            builder of uses statement
110      * @param module
111      *            current module
112      * @param context
113      *            SchemaContext containing already resolved modules
114      * @return grouping with given name if found, null otherwise
115      */
116     public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
117             final ModuleBuilder module, final SchemaContext context) {
118         final int line = usesBuilder.getLine();
119         String groupingString = usesBuilder.getGroupingPathAsString();
120         String groupingPrefix;
121         String groupingName;
122
123         if (groupingString.contains(":")) {
124             String[] splitted = groupingString.split(":");
125             if (splitted.length != 2 || groupingString.contains("/")) {
126                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
127             }
128             groupingPrefix = splitted[0];
129             groupingName = splitted[1];
130         } else {
131             groupingPrefix = module.getPrefix();
132             groupingName = groupingString;
133         }
134
135         Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line);
136         return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
137     }
138
139     /**
140      * Find grouping by name.
141      *
142      * @param groupings
143      *            collection of grouping builders to search
144      * @param name
145      *            name of grouping
146      * @return grouping with given name if present in collection, null otherwise
147      */
148     public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
149         for (GroupingBuilder grouping : groupings) {
150             if (grouping.getQName().getLocalName().equals(name)) {
151                 return grouping;
152             }
153         }
154         return null;
155     }
156
157     /**
158      * Find grouping by name.
159      *
160      * @param groupings
161      *            collection of grouping definitions to search
162      * @param name
163      *            name of grouping
164      * @return grouping with given name if present in collection, null otherwise
165      */
166     public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
167         for (GroupingDefinition grouping : groupings) {
168             if (grouping.getQName().getLocalName().equals(name)) {
169                 return grouping;
170             }
171         }
172         return null;
173     }
174
175     /**
176      * Perform refinement of uses target grouping nodes. Uses process has to be
177      * already performed.
178      *
179      * @param usesNode
180      *            uses node containing refine statements
181      */
182     public static void performRefine(UsesNodeBuilder usesNode) {
183         for (RefineHolder refine : usesNode.getRefines()) {
184             String refineTargetPath = refine.getName();
185
186             String[] splitted = refineTargetPath.split("/");
187             Builder currentNode = usesNode.getParent();
188             for (String pathElement : splitted) {
189                 if (currentNode instanceof DataNodeContainerBuilder) {
190                     currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
191                 } else if (currentNode instanceof ChoiceBuilder) {
192                     currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
193                 }
194             }
195
196             DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
197             if (nodeToRefine == null) {
198                 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
199                         + refine.getName() + "' not found");
200             }
201             RefineUtils.performRefine(nodeToRefine, refine);
202             usesNode.addRefineNode(nodeToRefine);
203         }
204     }
205
206     public static class UsesComparator implements Comparator<UsesNodeBuilder> {
207         @Override
208         public int compare(UsesNodeBuilder o1, UsesNodeBuilder o2) {
209             return getElementPosition(o2) - getElementPosition(o1);
210         }
211     }
212
213     private static int getElementPosition(UsesNodeBuilder usesNode) {
214         int i = 0;
215         Builder parent = usesNode.getParent();
216         while (!(parent instanceof ModuleBuilder)) {
217             parent = parent.getParent();
218             i++;
219         }
220         return i;
221     }
222
223 }