/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.parser.util; import java.net.URI; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; import org.opendaylight.yangtools.yang.model.util.ExtendedType; import org.opendaylight.yangtools.yang.parser.builder.api.Builder; import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember; import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder; public final class GroupingUtils { private GroupingUtils() { } /** * Search given modules for grouping by name defined in uses node. * * @param usesBuilder * builder of uses statement * @param modules * all loaded modules * @param module * current module * @return grouping with given name if found, null otherwise */ public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder, final Map> modules, final ModuleBuilder module) { final int line = usesBuilder.getLine(); final String groupingString = usesBuilder.getGroupingPathAsString(); String groupingPrefix; String groupingName; if (groupingString.contains(":")) { String[] splitted = groupingString.split(":"); if (splitted.length != 2 || groupingString.contains("/")) { throw new YangParseException(module.getName(), line, "Invalid name of target grouping"); } groupingPrefix = splitted[0]; groupingName = splitted[1]; } else { groupingPrefix = module.getPrefix(); groupingName = groupingString; } ModuleBuilder dependentModule; if (groupingPrefix.equals(module.getPrefix())) { dependentModule = module; } else { dependentModule = ParserUtils.findModuleFromBuilders(modules, module, groupingPrefix, line); } if (dependentModule == null) { return null; } GroupingBuilder result; Set groupings = dependentModule.getGroupingBuilders(); result = findGroupingBuilder(groupings, groupingName); if (result != null) { return result; } Builder parent = usesBuilder.getParent(); while (parent != null) { if (parent instanceof DataNodeContainerBuilder) { groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders(); } else if (parent instanceof RpcDefinitionBuilder) { groupings = ((RpcDefinitionBuilder) parent).getGroupings(); } result = findGroupingBuilder(groupings, groupingName); if (result == null) { parent = parent.getParent(); } else { break; } } if (result == null) { throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName + "' not found."); } return result; } /** * Search context for grouping by name defined in uses node. * * @param usesBuilder * builder of uses statement * @param module * current module * @param context * SchemaContext containing already resolved modules * @return grouping with given name if found, null otherwise */ public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder, final ModuleBuilder module, final SchemaContext context) { final int line = usesBuilder.getLine(); String groupingString = usesBuilder.getGroupingPathAsString(); String groupingPrefix; String groupingName; if (groupingString.contains(":")) { String[] splitted = groupingString.split(":"); if (splitted.length != 2 || groupingString.contains("/")) { throw new YangParseException(module.getName(), line, "Invalid name of target grouping"); } groupingPrefix = splitted[0]; groupingName = splitted[1]; } else { groupingPrefix = module.getPrefix(); groupingName = groupingString; } Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line); return findGroupingDefinition(dependentModule.getGroupings(), groupingName); } /** * Find grouping by name. * * @param groupings * collection of grouping builders to search * @param name * name of grouping * @return grouping with given name if present in collection, null otherwise */ public static GroupingBuilder findGroupingBuilder(Set groupings, String name) { for (GroupingBuilder grouping : groupings) { if (grouping.getQName().getLocalName().equals(name)) { return grouping; } } return null; } /** * Find grouping by name. * * @param groupings * collection of grouping definitions to search * @param name * name of grouping * @return grouping with given name if present in collection, null otherwise */ public static GroupingDefinition findGroupingDefinition(Set groupings, String name) { for (GroupingDefinition grouping : groupings) { if (grouping.getQName().getLocalName().equals(name)) { return grouping; } } return null; } /** * Read data defined in target grouping definition, make a copy and add them * to uses node builder. * * @param usesNode * used node builder to which are copied nodes from its * GroupingDefinition * @param namespace * URI with parent namespace * @param revision * date with parent revision date * @param prefix * string with parent prefix * @param moduleName * string with parent module name * @param line * line from YANG file where parent node is defined */ public static Set getTargetGroupingDefinitionNodesWithNewNamespace( final UsesNodeBuilder usesNode, final URI namespace, final Date revision, final String prefix, final String moduleName, final int line) { final Set newChildren = new HashSet<>(); for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) { if (child != null) { DataSchemaNodeBuilder newChild = null; QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName()); if (child instanceof AnyXmlSchemaNode) { newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line); } else if (child instanceof ChoiceNode) { newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, line); } else if (child instanceof ContainerSchemaNode) { newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, line); } else if (child instanceof LeafListSchemaNode) { newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, line); } else if (child instanceof LeafSchemaNode) { newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line); } else if (child instanceof ListSchemaNode) { newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, line); } if (newChild == null) { throw new YangParseException(moduleName, line, "Unknown member of target grouping while resolving uses node."); } ((GroupingMember) newChild).setAddedByUses(true); newChildren.add(newChild); } } return newChildren; } public static Set getTargetGroupingDefinitionTypedefsWithNewNamespace( UsesNodeBuilder usesNode, URI namespace, Date revision, String prefix, String moduleName, int line) { final Set newTypedefs = new HashSet<>(); for (TypeDefinition td : usesNode.getGroupingDefinition().getTypeDefinitions()) { QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName()); TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line); newType.setAddedByUses(true); newTypedefs.add(newType); } return newTypedefs; } public static Set getTargetGroupingDefinitionGroupingsWithNewNamespace(UsesNodeBuilder usesNode, URI namespace, Date revision, String prefix, String moduleName, int line) { final Set newGroupings = new HashSet<>(); for (GroupingDefinition g : usesNode.getGroupingDefinition().getGroupings()) { QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName()); GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line); newGrouping.setAddedByUses(true); newGroupings.add(newGrouping); } return newGroupings; } public static List getTargetGroupingDefinitionUnknownNodesWithNewNamespace( UsesNodeBuilder usesNode, URI namespace, Date revision, String prefix, String moduleName, int line) { final List newUnknownNodes = new ArrayList<>(); for (UnknownSchemaNode un : usesNode.getGroupingDefinition().getUnknownSchemaNodes()) { QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName()); UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line); newNode.setAddedByUses(true); newUnknownNodes.add(newNode); } return newUnknownNodes; } /** * Perform refinement of uses target grouping nodes. Uses process has to be * already performed. * * @param usesNode * uses node containing refine statements */ public static void performRefine(UsesNodeBuilder usesNode) { for (RefineHolder refine : usesNode.getRefines()) { String refineTargetPath = refine.getName(); String[] splitted = refineTargetPath.split("/"); Builder currentNode = usesNode.getParent(); for (String pathElement : splitted) { if (currentNode instanceof DataNodeContainerBuilder) { currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement); } else if (currentNode instanceof ChoiceBuilder) { currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement); } } DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode; if (nodeToRefine == null) { throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '" + refine.getName() + "' not found"); } RefineUtils.performRefine(nodeToRefine, refine); usesNode.addRefineNode(nodeToRefine); } } public static class UsesComparator implements Comparator { @Override public int compare(UsesNodeBuilder o1, UsesNodeBuilder o2) { return getElementPosition(o2) - getElementPosition(o1); } } private static int getElementPosition(UsesNodeBuilder usesNode) { int i = 0; Builder parent = usesNode.getParent(); while (!(parent instanceof ModuleBuilder)) { parent = parent.getParent(); i++; } return i; } }