f214d56220bf92827a7480149687773b7629d108
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / binding / yang / types / GroupingDefinitionDependencySort.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.binding.yang.types;
9
10 import com.google.common.collect.Maps;
11 import com.google.common.collect.Sets;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import org.opendaylight.yangtools.util.TopologicalSort;
19 import org.opendaylight.yangtools.util.TopologicalSort.Node;
20 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
22 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
26 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
27 import org.opendaylight.yangtools.yang.model.api.UsesNode;
28
29 public class GroupingDefinitionDependencySort {
30
31     /**
32      * Sorts set <code>groupingDefinitions</code> according to the mutual
33      * dependencies.<br>
34      *
35      * Elements of <code>groupingDefinitions</code> are firstly transformed to
36      * {@link TopologicalSort.Node Node} interfaces and then are sorted by
37      * {@link TopologicalSort#sort(Set) sort()} method of <code>TopologicalSort</code>.<br>
38      * <br>
39      *
40      * <i>Definition of dependency relation:<br>
41      * The first <code>GroupingDefinition</code> object (in this context)
42      * depends on second <code>GroupingDefinition</code> object if the first one
43      * contains in its set of <code>UsesNode</code> (obtained through
44      * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer#getUses()
45      * getUses} method) reference to the second one.</i>
46      *
47      * @param groupingDefinitions
48      *            set of grouping definition which should be sorted according to
49      *            mutual dependencies
50      * @return list of grouping definitiond which are sorted by mutual
51      *         dependencies
52      * @throws IllegalArgumentException
53      *             if <code>groupingDefinitions</code>
54      *
55      */
56     public List<GroupingDefinition> sort(final Collection<GroupingDefinition> groupingDefinitions) {
57         if (groupingDefinitions == null) {
58             throw new IllegalArgumentException("Set of Type Definitions " + "cannot be NULL!");
59         }
60
61         final List<GroupingDefinition> resultGroupingDefinitions = new ArrayList<>();
62         final Set<Node> unsorted = groupingDefinitionsToNodes(groupingDefinitions);
63         final List<Node> sortedNodes = TopologicalSort.sort(unsorted);
64         for (Node node : sortedNodes) {
65             NodeWrappedType nodeWrappedType = (NodeWrappedType) node;
66             resultGroupingDefinitions.add((GroupingDefinition) nodeWrappedType.getWrappedType());
67         }
68         return resultGroupingDefinitions;
69
70     }
71
72     /**
73      * Wraps every grouping definition to node type and adds to every node
74      * information about dependencies.
75      *
76      * The map with mapping from schema path (represents grouping definition) to
77      * node is created. For every created node (next <i>nodeFrom</i>) is for its
78      * wrapped grouping definition passed the set of its <i>uses nodes</i>
79      * through. For every uses node is found its wrapping node (next as
80      * <i>nodeTo</i>). This dependency relationship between nodeFrom and all
81      * found nodesTo is modeled with creating of one edge from nodeFrom to
82      * nodeTo.
83      *
84      *
85      * @param groupingDefinitions
86      *            set of goruping definition which will be wrapped to nodes
87      *
88      * @return set of nodes where every one contains wrapped grouping definition
89      */
90     private Set<Node> groupingDefinitionsToNodes(final Collection<GroupingDefinition> groupingDefinitions) {
91         final Map<SchemaPath, Node> nodeMap = Maps.newHashMap();
92         final Set<Node> resultNodes = Sets.newHashSet();
93
94         for (final GroupingDefinition groupingDefinition : groupingDefinitions) {
95             final Node node = new NodeWrappedType(groupingDefinition);
96             nodeMap.put(groupingDefinition.getPath(), node);
97             resultNodes.add(node);
98         }
99
100         for (final Node node : resultNodes) {
101             final NodeWrappedType nodeWrappedType = (NodeWrappedType) node;
102             final GroupingDefinition groupingDefinition = (GroupingDefinition) nodeWrappedType.getWrappedType();
103
104             Set<UsesNode> usesNodes = getAllUsesNodes(groupingDefinition);
105
106             for (UsesNode usesNode : usesNodes) {
107                 SchemaPath schemaPath = usesNode.getGroupingPath();
108                 if (schemaPath != null) {
109                     Node nodeTo = nodeMap.get(schemaPath);
110                     if (nodeTo != null) {
111                         nodeWrappedType.addEdge(nodeTo);
112                     }
113                 }
114             }
115         }
116
117         return resultNodes;
118     }
119
120     /**
121      * Returns the set of the uses nodes which are get from uses in
122      * <code>container</code>, from uses in groupings inside
123      * <code>container</code> and from uses inside child nodes of the
124      * <code>container</code>.
125      *
126      * @param container
127      *            data node container which can contain some uses of grouping
128      * @return set of uses nodes which were find in <code>container</code>.
129      */
130     private Set<UsesNode> getAllUsesNodes(final DataNodeContainer container) {
131         Set<UsesNode> ret = new HashSet<>();
132         Set<UsesNode> usesNodes = container.getUses();
133         ret.addAll(usesNodes);
134
135         for (UsesNode usesNode : usesNodes) {
136             for (AugmentationSchema augment : usesNode.getAugmentations()) {
137                 ret.addAll(getAllUsesNodes(augment));
138             }
139         }
140         Set<GroupingDefinition> groupings = container.getGroupings();
141         for (GroupingDefinition groupingDefinition : groupings) {
142             ret.addAll(getAllUsesNodes(groupingDefinition));
143         }
144         for (DataSchemaNode childNode : container.getChildNodes()) {
145             if (childNode instanceof DataNodeContainer) {
146                 ret.addAll(getAllUsesNodes((DataNodeContainer) childNode));
147             } else if (childNode instanceof ChoiceSchemaNode) {
148                 Set<ChoiceCaseNode> cases = ((ChoiceSchemaNode) childNode).getCases();
149                 for (ChoiceCaseNode choiceCaseNode : cases) {
150                     ret.addAll(getAllUsesNodes(choiceCaseNode));
151                 }
152             }
153         }
154         return ret;
155     }
156
157 }