// This product is provided under the terms of EPL (Eclipse Public License)
// version 1.0.
//
// The full license text can be read from: http://www.eclipse.org/org/documents/epl-v10.php
package org.dtangler.core.cycleanalysis;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.dtangler.core.analysis.DependencyAnalyzer;
import org.dtangler.core.dependencies.Dependable;
import org.dtangler.core.dependencies.Dependencies;
import org.dtangler.core.dependencies.Dependency;
import org.dtangler.core.dependencies.DependencyGraph;
import org.dtangler.core.dependencies.DependencyPath;
import org.dtangler.core.dependencies.Scope;
public class CycleValidator extends DependencyAnalyzer {
private final Set<Dependency> processedItems = new HashSet();
private final boolean cyclesAllowed;
private int stepCount = 0;
public CycleValidator(boolean cyclesAllowed) {
this.cyclesAllowed = cyclesAllowed;
}
private void findCycles(Dependable item, DependencyGraph dependencies) {
Set<Dependable> deps = dependencies.getDependencies(item);
for (Dependable dep : deps)
findCycles(item, createPath(new DependencyPath(Collections
.singletonList(item)), dep), dep, dependencies);
}
private DependencyPath createPath(DependencyPath prevPath,
Dependable nextItem) {
DependencyPath path = new DependencyPath(prevPath.getItems());
path.addItem(nextItem);
return path;
}
private void findCycles(Dependable item, DependencyPath path,
Dependable dep, DependencyGraph dependencies) {
Set<Dependable> childDeps = dependencies.getDependencies(dep);
Dependency dependency = path.getDependencyByDependee(dep);
if (processedItems.contains(dependency))
return;
stepCount++;
for (Dependable childDep : childDeps) {
if (path.contains(childDep)) {
addCycle(childDep, path);
} else {
findCycles(item, createPath(path, childDep), childDep,
dependencies);
}
}
processedItems.add(dependency);
}
private void addCycle(Dependable item, DependencyPath path) {
List<Dependable> pathItems = path.getItems();
List<Dependable> cycleMembers = pathItems.subList(pathItems
.indexOf(item), pathItems.size());
for (int i = 0; i < cycleMembers.size(); i++) {
Dependable dependant = cycleMembers.get(i);
Dependable dependee = getDependee(i, cycleMembers);
Dependency dependency = new Dependency(dependant, dependee);
DependencyCycle cycle = createCycle(dependant, cycleMembers);
addViolation(dependency, cycle);
}
}
private Dependable getDependee(int index, List<Dependable> cycleMembers) {
if (index >= cycleMembers.size() - 1)
return cycleMembers.get(0);
return cycleMembers.get(index + 1);
}
private DependencyCycle createCycle(Dependable cycleMember,
List<Dependable> cycleMembers) {
List<Dependable> cycle = new ArrayList();
cycle.add(cycleMember);
int index = cycleMembers.indexOf(cycleMember);
int count = cycleMembers.size();
if (index < cycleMembers.size() - 1)
cycle.addAll(cycleMembers.subList(index + 1, count));
if (index > 0)
cycle.addAll(cycleMembers.subList(0, index));
cycle.add(cycleMember);
return new DependencyCycle(cycle);
}
// for test purposes
int stepCount() {
return stepCount;
}
@Override
public void doAnalyze(Dependencies dependencies) {
for (Scope scope : dependencies.getAvailableScopes()) {
analyze(dependencies.getDependencyGraph(scope));
}
}
private void analyze(DependencyGraph dependencies) {
processedItems.clear();
Set<Dependable> items = dependencies.getAllItems();
for (Dependable dep : items) {
findCycles(dep, dependencies);
}
}
public boolean isValidResult() {
if (cyclesAllowed)
return true;
return getViolations().isEmpty();
}
}