/* * 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.mdsal.binding.yang.types; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.opendaylight.yangtools.util.TopologicalSort; import org.opendaylight.yangtools.util.TopologicalSort.Node; import org.opendaylight.yangtools.yang.model.api.ActionDefinition; import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer; import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.UsesNode; public class GroupingDefinitionDependencySort { /** * Sorts set {@code groupingDefinitions} according to the mutual dependencies.
* Elements of {@code groupingDefinitions} are firstly transformed to {@link Node} interfaces and then are * sorted by {@link TopologicalSort#sort(Set) sort()} method of {@code TopologicalSort}.
* * Definition of dependency relation:
* The first {@code GroupingDefinition} object (in this context) depends on second {@code GroupingDefinition} object * if the first one contains in its set of {@code UsesNode} (obtained through {@link DataNodeContainer#getUses()}) * a 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 {@code groupingDefinitions} * */ public List sort(final Collection groupingDefinitions) { if (groupingDefinitions == null) { throw new IllegalArgumentException("Set of Type Definitions cannot be NULL!"); } final List sortedNodes = TopologicalSort.sort(groupingDefinitionsToNodes(groupingDefinitions)); final List resultGroupingDefinitions = new ArrayList<>(sortedNodes.size()); for (Node node : sortedNodes) { NodeWrappedType nodeWrappedType = (NodeWrappedType) node; resultGroupingDefinitions.add((GroupingDefinition) 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 grouping definition which will be wrapped to nodes * @return set of nodes where every one contains wrapped grouping definition */ private Set groupingDefinitionsToNodes(final Collection groupingDefinitions) { final Map nodeMap = new HashMap<>(); final Set resultNodes = new HashSet<>(); for (final GroupingDefinition 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 GroupingDefinition groupingDefinition = (GroupingDefinition) nodeWrappedType.getWrappedType(); Set usesNodes = getAllUsesNodes(groupingDefinition); for (UsesNode usesNode : usesNodes) { SchemaPath schemaPath = usesNode.getGroupingPath(); if (schemaPath != null) { Node nodeTo = nodeMap.get(schemaPath); if (nodeTo != null) { 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. */ private Set getAllUsesNodes(final DataNodeContainer container) { Set ret = new HashSet<>(); Set usesNodes = container.getUses(); ret.addAll(usesNodes); for (UsesNode usesNode : usesNodes) { for (AugmentationSchemaNode augment : usesNode.getAugmentations()) { ret.addAll(getAllUsesNodes(augment)); } } for (GroupingDefinition groupingDefinition : container.getGroupings()) { ret.addAll(getAllUsesNodes(groupingDefinition)); } for (DataSchemaNode childNode : container.getChildNodes()) { if (childNode instanceof DataNodeContainer) { ret.addAll(getAllUsesNodes((DataNodeContainer) childNode)); } else if (childNode instanceof ChoiceSchemaNode) { for (CaseSchemaNode choiceCaseNode : ((ChoiceSchemaNode) childNode).getCases().values()) { ret.addAll(getAllUsesNodes(choiceCaseNode)); } } } if (container instanceof ActionNodeContainer) { for (ActionDefinition action : ((ActionNodeContainer) container).getActions()) { ret.addAll(getAllUsesNodes(action.getInput())); ret.addAll(getAllUsesNodes(action.getOutput())); } } if (container instanceof NotificationNodeContainer) { for (NotificationDefinition notification : ((NotificationNodeContainer) container).getNotifications()) { ret.addAll(getAllUsesNodes(notification)); } } return ret; } }