package org.codefx.mvn.jdeps.result;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.codefx.mvn.jdeps.dependency.InternalType;
import org.codefx.mvn.jdeps.dependency.Type;
import org.codefx.mvn.jdeps.dependency.Violation;
import org.codefx.mvn.jdeps.rules.Severity;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
/**
* A violation whose dependencies are annotated with their severity.
*/
final class AnnotatedViolation {
private final Type dependent;
private ImmutableMap<Severity, ImmutableList<InternalType>> internalDependencies;
private AnnotatedViolation(
Type dependent,
ImmutableMap<Severity, ImmutableList<InternalType>> internalDependencies) {
this.dependent = dependent;
this.internalDependencies = internalDependencies;
}
public static AnnotatedViolation of(Type dependent, ImmutableList<AnnotatedInternalType> internalDependencies) {
requireNonNull(dependent, "The argument 'dependent' must not be null.");
requireNonNull(internalDependencies, "The argument 'internalDependencies' must not be null.");
if (internalDependencies.size() == 0)
throw new IllegalArgumentException(
"A violation must contain at least one internal dependency.");
ImmutableMap<Severity, ImmutableList<InternalType>> internalDependenciesMap =
internalDependencies.stream().collect(
collectingAndThen(
groupingBy(AnnotatedInternalType::getSeverity,
collectingAndThen(mapping(
AnnotatedInternalType::getType,
toList()),
ImmutableList::copyOf)),
ImmutableMap::copyOf));
return new AnnotatedViolation(dependent, internalDependenciesMap);
}
/**
* Returns a violation that contains only the internal dependencies with the specified severities.
* <p>
* If no internal dependencies for the specified severities exist, {@link Optional#empty()} is returned.
*
* @param severities
* the severities to filterBy internal dependencies by
*
* @return a violation or {@link Optional#empty() empty} if no internal dependencies with the specified severity
* exist
*/
public Optional<Violation> only(Severity... severities) {
List<Severity> severitiesToSelect = Arrays.asList(severities);
return filterBy(severitiesToSelect::contains);
}
/**
* Returns a violation that contains all internal dependencies except the ones with one of the specified
* severities.
*
* @return a violation or {@link Optional#empty() empty} if no internal dependencies with the non-excluded
* severities exist
*/
public Optional<Violation> except(Severity... severities) {
List<Severity> severitiesToIgnore = Arrays.asList(severities);
return filterBy(severity -> !severitiesToIgnore.contains(severity));
}
private Optional<Violation> filterBy(Predicate<Severity> filterBySeverity) {
List<InternalType> dependencies = Severity.stream()
.filter(filterBySeverity)
.map(internalDependencies::get)
.filter(Objects::nonNull)
.flatMap(ImmutableList::stream)
.collect(toList());
if (dependencies.isEmpty())
return Optional.empty();
else
return Optional.of(Violation.buildFor(dependent, dependencies));
}
}