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.builder.impl;
10 import com.google.common.base.Splitter;
12 import java.util.Comparator;
13 import java.util.Date;
14 import java.util.Iterator;
17 import java.util.TreeMap;
19 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
22 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
23 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
24 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
25 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
28 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
30 public final class GroupingUtils {
31 private static final Splitter COLON_SPLITTER = Splitter.on(':');
32 private static final Splitter SLASH_SPLITTER = Splitter.on('/');
34 private GroupingUtils() {
38 * Common string splitter. Given a string representation of a grouping's name, it creates a prefix/name
39 * pair and returns it.
41 * @param groupingString Grouping string reference
42 * @param module Module which we are processing
43 * @param line Module line which we are processing
44 * @return An array of two strings, first one is the module prefix, the second is the grouping name.
46 private static String[] getPrefixAndName(final String groupingString, final ModuleBuilder module, final int line) {
47 final String[] ret = new String[2];
49 if (groupingString.indexOf(':') != -1) {
50 if (groupingString.indexOf('/') != -1) {
51 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
54 final Iterator<String> split = COLON_SPLITTER.split(groupingString).iterator();
55 ret[0] = split.next();
56 ret[1] = split.next();
57 if (split.hasNext()) {
58 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
61 ret[0] = module.getPrefix();
62 ret[1] = groupingString;
69 * Search given modules for grouping by name defined in uses node.
72 * builder of uses statement
77 * @return grouping with given name if found, null otherwise
79 public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
80 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
81 final int line = usesBuilder.getLine();
83 final String[] split = getPrefixAndName(usesBuilder.getGroupingPathAsString(), module, line);
84 final String groupingPrefix = split[0];
85 final String groupingName = split[1];
86 final ModuleBuilder dependentModule;
88 if (groupingPrefix == null) {
89 dependentModule = module;
90 } else if (groupingPrefix.equals(module.getPrefix())) {
91 dependentModule = module;
93 dependentModule = BuilderUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
96 if (dependentModule == null) {
100 GroupingBuilder result;
101 Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
102 result = findGroupingBuilder(groupings, groupingName);
103 if (result != null) {
107 Builder parent = usesBuilder.getParent();
109 while (parent != null) {
110 if (parent instanceof DataNodeContainerBuilder) {
111 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
112 } else if (parent instanceof RpcDefinitionBuilder) {
113 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
115 result = findGroupingBuilder(groupings, groupingName);
116 if (result == null) {
117 parent = parent.getParent();
123 if (result == null) {
124 throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
131 * Search context for grouping by name defined in uses node.
134 * builder of uses statement
138 * SchemaContext containing already resolved modules
139 * @return grouping with given name if found, null otherwise
141 public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
142 final ModuleBuilder module, final SchemaContext context) {
143 final int line = usesBuilder.getLine();
144 final String[] split = getPrefixAndName(usesBuilder.getGroupingPathAsString(), module, line);
145 Module dependentModule = BuilderUtils.findModuleFromContext(context, module, split[0], line);
146 return findGroupingDefinition(dependentModule.getGroupings(), split[1]);
150 * Find grouping by name.
153 * collection of grouping builders to search
156 * @return grouping with given name if present in collection, null otherwise
158 private static GroupingBuilder findGroupingBuilder(final Set<GroupingBuilder> groupings, final String name) {
159 for (GroupingBuilder grouping : groupings) {
160 if (grouping.getQName().getLocalName().equals(name)) {
168 * Find grouping by name.
171 * collection of grouping definitions to search
174 * @return grouping with given name if present in collection, null otherwise
176 private static GroupingDefinition findGroupingDefinition(final Set<GroupingDefinition> groupings, final String name) {
177 for (GroupingDefinition grouping : groupings) {
178 if (grouping.getQName().getLocalName().equals(name)) {
186 * Perform refinement of uses target grouping nodes. Uses process has to be
190 * uses node containing refine statements
192 public static void performRefine(final UsesNodeBuilder usesNode) {
193 for (RefineBuilder refine : usesNode.getRefines()) {
194 String refineTargetPath = refine.getTargetPathString();
196 Builder currentNode = usesNode.getParent();
197 for (String pathElement : SLASH_SPLITTER.split(refineTargetPath)) {
198 if (currentNode instanceof DataNodeContainerBuilder) {
199 currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
200 } else if (currentNode instanceof ChoiceBuilder) {
201 currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
205 DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
206 if (nodeToRefine == null) {
207 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
208 + refine.getTargetPathString() + "' not found");
210 RefineUtils.performRefine(nodeToRefine, refine);
211 usesNode.addRefineNode(nodeToRefine);
215 public static class UsesComparator implements Comparator<UsesNodeBuilder> {
217 public int compare(final UsesNodeBuilder o1, final UsesNodeBuilder o2) {
218 return getElementPosition(o2) - getElementPosition(o1);
222 private static int getElementPosition(final UsesNodeBuilder usesNode) {
224 Builder parent = usesNode.getParent();
225 while (!(parent instanceof ModuleBuilder)) {
226 parent = parent.getParent();