/*
* 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 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.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
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.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.UsesNode;
import org.opendaylight.yangtools.yang.parser.util.TopologicalSort;
import org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node;
public class GroupingDefinitionDependencySort {
/**
* 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 definitiond which are sorted by mutual
* dependencies
* @throws IllegalArgumentException
* if groupingDefinitions
*
*/
public 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((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 goruping 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 = Maps.newHashMap();
final Set resultNodes = Sets.newHashSet();
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 (AugmentationSchema augment : usesNode.getAugmentations()) {
ret.addAll(getAllUsesNodes(augment));
}
}
Set groupings = container.getGroupings();
for (GroupingDefinition groupingDefinition : groupings) {
ret.addAll(getAllUsesNodes(groupingDefinition));
}
for (DataSchemaNode childNode : container.getChildNodes()) {
if (childNode instanceof DataNodeContainer) {
ret.addAll(getAllUsesNodes((DataNodeContainer) childNode));
} else if (childNode instanceof ChoiceSchemaNode) {
Set cases = ((ChoiceSchemaNode) childNode).getCases();
for (ChoiceCaseNode choiceCaseNode : cases) {
ret.addAll(getAllUsesNodes(choiceCaseNode));
}
}
}
return ret;
}
}