/* * 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.impl; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder; 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.UsesNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder; import org.opendaylight.yangtools.yang.parser.util.NodeWrappedType; import org.opendaylight.yangtools.yang.parser.util.TopologicalSort; import org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node; public final class GroupingSort { private GroupingSort() { throw new UnsupportedOperationException("Utility class should not be instantiated"); } /** * Sorts set groupingDefinitions according to the mutual * dependencies.
* * Elements of groupingDefinitions are firstly transformed to * {@link org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node * Node} interfaces and then are sorted by * {@link org.opendaylight.yangtools.yang.parser.util.TopologicalSort#sort(Set) * sort()} method of TopologicalSort.
*
* * * Definition of dependency relation:
* The first GroupingDefinition object (in this context) * depends on second GroupingDefinition object if the first one * contains in its set of UsesNode (obtained through * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer#getUses() * getUses} method) reference to the second one.
* * @param groupingDefinitions * set of grouping definition which should be sorted according to * mutual dependencies * @return list of grouping definitions which are sorted by mutual * dependencies * @throws IllegalArgumentException * if groupingDefinitions * */ public static List sort(final Collection groupingDefinitions) { if (groupingDefinitions == null) { throw new IllegalArgumentException("Set of Type Definitions " + "cannot be NULL!"); } final List resultGroupingDefinitions = new ArrayList<>(); final Set unsorted = groupingDefinitionsToNodes(groupingDefinitions); final List sortedNodes = TopologicalSort.sort(unsorted); for (Node node : sortedNodes) { NodeWrappedType nodeWrappedType = (NodeWrappedType) node; resultGroupingDefinitions.add((GroupingBuilder) (nodeWrappedType.getWrappedType())); } return resultGroupingDefinitions; } /** * Wraps every grouping definition to node type and adds to every node * information about dependencies. * * The map with mapping from schema path (represents grouping definition) to * node is created. For every created node (next nodeFrom) is for its * wrapped grouping definition passed the set of its uses nodes * through. For every uses node is found its wrapping node (next as * nodeTo). This dependency relationship between nodeFrom and all * found nodesTo is modeled with creating of one edge from nodeFrom to * nodeTo. * * * @param groupingDefinitions * set of goruping definition which will be wrapped to nodes * * @return set of nodes where every one contains wrapped grouping definition */ private static Set groupingDefinitionsToNodes(final Collection groupingDefinitions) { final Map nodeMap = Maps.newHashMap(); final Set resultNodes = Sets.newHashSet(); for (final GroupingBuilder groupingDefinition : groupingDefinitions) { final Node node = new NodeWrappedType(groupingDefinition); nodeMap.put(groupingDefinition.getPath(), node); resultNodes.add(node); } for (final Node node : resultNodes) { final NodeWrappedType nodeWrappedType = (NodeWrappedType) node; final GroupingBuilder groupingDefinition = (GroupingBuilder) nodeWrappedType.getWrappedType(); Set usesNodes = getAllUsesNodes(groupingDefinition); for (UsesNodeBuilder usesNode : usesNodes) { SchemaPath schemaPath = usesNode.getGroupingBuilder().getPath(); Node nodeTo = nodeMap.get(schemaPath); if (nodeTo == null) { throw new IllegalArgumentException("target grouping not found for uses " + usesNode); } nodeWrappedType.addEdge(nodeTo); } } return resultNodes; } /** * Returns the set of the uses nodes which are get from uses in * container, from uses in groupings inside * container and from uses inside child nodes of the * container. * * @param container * data node container which can contain some uses of grouping * @return set of uses nodes which were find in container. */ public static Set getAllUsesNodes(final DataNodeContainerBuilder container) { Set ret = new HashSet<>(); Set usesNodes = container.getUsesNodeBuilders(); ret.addAll(usesNodes); for (UsesNodeBuilder usesNode : usesNodes) { for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { ret.addAll(getAllUsesNodes(augment)); } } Set groupings = container.getGroupingBuilders(); for (GroupingBuilder groupingDefinition : groupings) { ret.addAll(getAllUsesNodes(groupingDefinition)); } Set childNodes = container.getChildNodeBuilders(); for (DataSchemaNodeBuilder childNode : childNodes) { if (childNode instanceof DataNodeContainerBuilder) { ret.addAll(getAllUsesNodes((DataNodeContainerBuilder) childNode)); } else if (childNode instanceof ChoiceBuilder) { Set cases = ((ChoiceBuilder) childNode).getCases(); for (ChoiceCaseBuilder choiceCaseNode : cases) { ret.addAll(getAllUsesNodes(choiceCaseNode)); } } } return ret; } }