aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java
blob: 0fc761d4c69b026268026e5b766a7b7bd2d4ec62 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onlab.jdvue;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import static com.google.common.base.MoreObjects.toStringHelper;

/**
 * Simple representation of a Java package dependency cycle.
 */
public class DependencyCycle {

    private final List<JavaPackage> cycle;

    /**
     * Creates a normalized dependency cycle represented by the specified list
     * of Java packages, which are expected to be given in order of dependency.
     * List is assumed to be non-empty.
     *
     * @param cycle list of Java packages in the dependency cycle
     * @param cause Java package that caused the cycle
     */
    DependencyCycle(List<JavaPackage> cycle, JavaPackage cause) {
        this.cycle = normalize(cycle, cause);
    }

    /**
     * Produces a normalized dependency cycle list. Normalization is performed
     * by rotating the list so that the package with the least lexicographic
     * name is at the start of the list.
     *
     * @param cycle list of Java packages in the dependency cycle
     * @param cause Java package that caused the cycle
     * @return normalized cycle
     */
    private List<JavaPackage> normalize(List<JavaPackage> cycle, JavaPackage cause) {
        int start = cycle.indexOf(cause);
        List<JavaPackage> clone = new ArrayList<>(cycle.subList(start, cycle.size()));
        int leastIndex = findIndexOfLeastName(clone);
        Collections.rotate(clone, -leastIndex);
        return Collections.unmodifiableList(clone);
    }

    /**
     * Returns the index of the Java package with the least name.
     *
     * @param cycle list of Java packages in the dependency cycle
     * @return index of the least Java package name
     */
    private int findIndexOfLeastName(List<JavaPackage> cycle) {
        int leastIndex = 0;
        String leastName = cycle.get(leastIndex).name();
        for (int i = 1, n = cycle.size(); i < n; i++) {
            JavaPackage javaPackage = cycle.get(i);
            if (leastName.compareTo(javaPackage.name()) > 0) {
                leastIndex = i;
                leastName = javaPackage.name();
            }
        }
        return leastIndex;
    }

    /**
     * Returns the normalized Java package dependency cycle
     *
     * @return list of packages in the dependency cycle
     */
    public List<JavaPackage> getCycle() {
        return cycle;
    }

    /**
     * Returns the dependency cycle in form of individual dependencies.
     *
     * @return list of dependencies forming the cycle
     */
    public List<Dependency> getCycleSegments() {
        List<Dependency> dependencies = new ArrayList<>();
        for (int i = 0, n = cycle.size(); i < n; i++) {
            dependencies.add(new Dependency(cycle.get(i), cycle.get(i < n - 1 ? i + 1 : 0)));
        }
        return dependencies;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof DependencyCycle) {
            DependencyCycle that = (DependencyCycle) o;
            return Objects.equals(cycle, that.cycle);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return cycle.hashCode();
    }

    @Override
    public String toString() {
        return toStringHelper(this).add("cycle", cycle).toString();
    }

    public String toShortString() {
        StringBuilder sb = new StringBuilder("[");
        for (JavaPackage javaPackage : cycle) {
            sb.append(javaPackage.name()).append(", ");
        }
        if (sb.length() > 1) {
            sb.delete(sb.length() - 2, sb.length());
        }
        sb.append("]");
        return sb.toString();
    }

}