1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.model.building;
20  
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.LinkedHashMap;
26  import java.util.LinkedList;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  
32  
33  
34  @Deprecated(since = "4.0.0")
35  class Graph {
36  
37      final Map<String, Set<String>> graph = new LinkedHashMap<>();
38  
39      synchronized void addEdge(String from, String to) throws CycleDetectedException {
40          if (graph.computeIfAbsent(from, l -> new HashSet<>()).add(to)) {
41              List<String> cycle = visitCycle(graph, Collections.singleton(to), new HashMap<>(), new LinkedList<>());
42              if (cycle != null) {
43                  
44                  throw new CycleDetectedException(
45                          "Edge between '" + from + "' and '" + to + "' introduces to cycle in the graph", cycle);
46              }
47          }
48      }
49  
50      private enum DfsState {
51          VISITING,
52          VISITED
53      }
54  
55      private static List<String> visitCycle(
56              Map<String, Set<String>> graph,
57              Collection<String> children,
58              Map<String, DfsState> stateMap,
59              LinkedList<String> cycle) {
60          if (children != null) {
61              for (String v : children) {
62                  DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
63                  if (state == null) {
64                      cycle.addLast(v);
65                      List<String> ret = visitCycle(graph, graph.get(v), stateMap, cycle);
66                      if (ret != null) {
67                          return ret;
68                      }
69                      cycle.removeLast();
70                      stateMap.put(v, DfsState.VISITED);
71                  } else if (state == DfsState.VISITING) {
72                      
73                      int pos = cycle.lastIndexOf(v);
74                      List<String> ret = cycle.subList(pos, cycle.size());
75                      ret.add(v);
76                      return ret;
77                  }
78              }
79          }
80          return null;
81      }
82  
83      public static class CycleDetectedException extends Exception {
84          private final List<String> cycle;
85  
86          CycleDetectedException(String message, List<String> cycle) {
87              super(message);
88              this.cycle = cycle;
89          }
90  
91          public List<String> getCycle() {
92              return cycle;
93          }
94  
95          @Override
96          public String getMessage() {
97              return super.getMessage() + " " + String.join(" --> ", cycle);
98          }
99      }
100 }