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