2 * ============LICENSE_START=======================================================
\r
4 * ================================================================================
\r
5 * Copyright © 2017 AT&T Intellectual Property.
\r
6 * Copyright © 2017 Amdocs
\r
7 * All rights reserved.
\r
8 * ================================================================================
\r
9 * Licensed under the Apache License, Version 2.0 (the "License");
\r
10 * you may not use this file except in compliance with the License.
\r
11 * You may obtain a copy of the License at
\r
12 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
18 * ============LICENSE_END=========================================================
\r
20 * ECOMP and OpenECOMP are trademarks
\r
21 * and service marks of AT&T Intellectual Property.
\r
23 package org.openecomp.modelloader.entity.model;
\r
25 import jline.internal.Log;
\r
27 import org.openecomp.modelloader.entity.Artifact;
\r
29 import java.util.ArrayList;
\r
30 import java.util.Collection;
\r
31 import java.util.HashMap;
\r
32 import java.util.HashSet;
\r
33 import java.util.Iterator;
\r
34 import java.util.List;
\r
37 * Utility class to sort the given Models according to their dependencies.
\r
38 * Example: Given a list of Models [A, B, C] where B depends on A, and A depends
\r
39 * on C, the sorted result will be [C, A, B]
\r
41 public class ModelSorter {
\r
44 * Wraps a Model object to form dependencies other Models using Edges.
\r
47 private final ModelArtifact model;
\r
48 private final HashSet<Edge> inEdges;
\r
49 private final HashSet<Edge> outEdges;
\r
51 public Node(ModelArtifact model) {
\r
53 inEdges = new HashSet<Edge>();
\r
54 outEdges = new HashSet<Edge>();
\r
57 public Node addEdge(Node node) {
\r
58 Edge edge = new Edge(this, node);
\r
60 node.inEdges.add(edge);
\r
65 public String toString() {
\r
66 return model.getModelInvariantId();
\r
70 public boolean equals(Object other) {
\r
71 ModelArtifact otherModel = ((Node) other).model;
\r
72 return this.model.getModelInvariantId().equals(otherModel.getModelInvariantId());
\r
76 public int hashCode() {
\r
77 return this.model.getModelInvariantId().hashCode();
\r
83 * Represents a dependency between two Nodes.
\r
86 public final Node from;
\r
87 public final Node to;
\r
89 public Edge(Node from, Node to) {
\r
95 public boolean equals(Object obj) {
\r
96 Edge edge = (Edge) obj;
\r
97 return edge.from == from && edge.to == to;
\r
102 * Returns the list of models sorted by order of dependency.
\r
104 * @param originalList
\r
105 * the list that needs to be sorted
\r
106 * @return a list of sorted models
\r
108 public List<Artifact> sort(List<Artifact> originalList) {
\r
110 if (originalList.size() <= 1) {
\r
111 return originalList;
\r
114 Collection<Node> nodes = createNodes(originalList);
\r
115 Collection<Node> sortedNodes = sortNodes(nodes);
\r
117 List<Artifact> sortedModelsList = new ArrayList<Artifact>(sortedNodes.size());
\r
118 for (Node node : sortedNodes) {
\r
119 sortedModelsList.add(node.model);
\r
122 return sortedModelsList;
\r
126 * Create nodes from the list of models and their dependencies.
\r
129 * what the nodes creation is based upon
\r
130 * @return Collection of Node objects
\r
132 private Collection<Node> createNodes(Collection<Artifact> models) {
\r
134 // load list of models into a map, so we can later replace referenceIds with
\r
136 HashMap<String, ModelArtifact> versionIdToModelMap = new HashMap<String, ModelArtifact>();
\r
137 for (Artifact art : models) {
\r
138 ModelArtifact ma = (ModelArtifact) art;
\r
139 versionIdToModelMap.put(ma.getModelModelVerCombinedKey(), ma);
\r
142 HashMap<String, Node> nodes = new HashMap<String, Node>();
\r
143 // create a node for each model and its referenced models
\r
144 for (Artifact art : models) {
\r
145 ModelArtifact model = (ModelArtifact) art;
\r
147 // node might have been created by another model referencing it
\r
148 Node node = nodes.get(model.getModelModelVerCombinedKey());
\r
150 if (null == node) {
\r
151 node = new Node(model);
\r
152 nodes.put(model.getModelModelVerCombinedKey(), node);
\r
155 for (String referencedModelId : model.getDependentModelIds()) {
\r
156 // node might have been created by another model referencing it
\r
157 Node referencedNode = nodes.get(referencedModelId);
\r
159 if (null == referencedNode) {
\r
161 ModelArtifact referencedModel = versionIdToModelMap.get(referencedModelId);
\r
162 if (referencedModel == null) {
\r
163 Log.debug("ignoring " + referencedModelId);
\r
164 continue; // referenced model not supplied, no need to sort it
\r
166 referencedNode = new Node(referencedModel);
\r
167 nodes.put(referencedModelId, referencedNode);
\r
169 referencedNode.addEdge(node);
\r
173 return nodes.values();
\r
177 * Sorts the given Nodes by order of dependency.
\r
179 * @param originalList
\r
180 * the collection of nodes to be sorted
\r
181 * @return a sorted collection of the given nodes
\r
183 private Collection<Node> sortNodes(Collection<Node> unsortedNodes) {
\r
185 // L <- Empty list that will contain the sorted elements
\r
186 ArrayList<Node> nodeList = new ArrayList<Node>();
\r
188 // S <- Set of all nodes with no incoming edges
\r
189 HashSet<Node> nodeSet = new HashSet<Node>();
\r
190 for (Node unsortedNode : unsortedNodes) {
\r
191 if (unsortedNode.inEdges.size() == 0) {
\r
192 nodeSet.add(unsortedNode);
\r
196 // while S is non-empty do
\r
197 while (!nodeSet.isEmpty()) {
\r
198 // remove a node n from S
\r
199 Node node = nodeSet.iterator().next();
\r
200 nodeSet.remove(node);
\r
203 nodeList.add(node);
\r
205 // for each node m with an edge e from n to m do
\r
206 for (Iterator<Edge> it = node.outEdges.iterator(); it.hasNext();) {
\r
207 // remove edge e from the graph
\r
208 Edge edge = it.next();
\r
210 it.remove();// Remove edge from n
\r
211 to.inEdges.remove(edge);// Remove edge from m
\r
213 // if m has no other incoming edges then insert m into S
\r
214 if (to.inEdges.isEmpty()) {
\r
219 // Check to see if all edges are removed
\r
220 boolean cycle = false;
\r
221 for (Node node : unsortedNodes) {
\r
222 if (!node.inEdges.isEmpty()) {
\r
228 throw new RuntimeException(
\r
229 "Circular dependency present between models, topological sort not possible");
\r