Skip to content

Commit

Permalink
moditect#27 Adding ComponentReference to represent components on the …
Browse files Browse the repository at this point in the history
…"to" side of dependencies
  • Loading branch information
gunnarmorling committed Jan 29, 2019
1 parent 1279dc7 commit c73af1b
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static <T extends Node<T>> List<List<T>> detectStronglyConnectedComponent
* @param nodes
* @return a list of strongly connected components (SCCs) with a size > 1.
*/
public static <T extends Node<T>> List<Cycle<T>> detectCycles(Iterable<T> nodes) {
public static <T extends Node<T>> List<Cycle<T>> detectCycles(Iterable<? extends T> nodes) {
return new Tarjan<T>().detectStronglyConnectedComponents(nodes)
.stream()
.filter(cycle -> cycle.size() > 1)
Expand Down Expand Up @@ -96,7 +96,7 @@ public static <T extends Node<T>> int[][] computeAdjacencyMatrix(List<T> nodes)
* @param nodes the array of nodes
* @return the adjacency list for the given list of nodes
*/
public static <T extends Node<T>> int[][] computeAdjacencyList(Iterable<T> nodes) {
public static <T extends Node<T>> int[][] computeAdjacencyList(Iterable<? extends T> nodes) {

int[][] matrix;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/
public interface Node<T extends Node<T>> {

default Set<Dependency<T>> getOutgoingDependenciesTo(Iterable<T> nodes) {
default Set<Dependency<T>> getOutgoingDependenciesTo(Iterable<? extends T> nodes) {
return StreamSupport.stream(nodes.spliterator(), false)
.map(c -> getOutgoingDependencyTo(c))
.filter(Objects::nonNull)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ public class Tarjan<T extends Node<T>> {

private List<T> _artifacts;

public List<List<T>> detectStronglyConnectedComponents(Iterable<T> artifacts) {
public List<List<T>> detectStronglyConnectedComponents(Iterable<? extends T> artifacts) {
Objects.requireNonNull(artifacts);

_artifacts = asList(artifacts);
int[][] adjacencyList = GraphUtils.computeAdjacencyList(artifacts);
return executeTarjan(adjacencyList);
}

private static <R> List<R> asList(Iterable<R> iterable) {
private static <R> List<R> asList(Iterable<? extends R> iterable) {
List<R> list = new ArrayList<>();
iterable.forEach(list::add);
return list;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.moditect.deptective.internal.log.Log;
import org.moditect.deptective.internal.model.Component;
import org.moditect.deptective.internal.model.Components;
import org.moditect.deptective.internal.model.IdentifiableComponent;
import org.moditect.deptective.internal.model.PackageAssignedToMultipleComponentsException;
import org.moditect.deptective.internal.model.PackageDependencies;
import org.moditect.deptective.internal.model.PackagePattern;
Expand Down Expand Up @@ -189,7 +190,7 @@ public void onCompletingCompilation() {
throw new RuntimeException("Failed to write deptective.json file", e);
}

List<Cycle<Component>> cycles = GraphUtils.detectCycles(packageDependencies.getComponents());
List<Cycle<IdentifiableComponent>> cycles = GraphUtils.detectCycles(packageDependencies.getComponents());

if (!cycles.isEmpty()) {
String cyclesAsString = "- " + cycles.stream()
Expand All @@ -202,9 +203,9 @@ public void onCompletingCompilation() {
if (createDotFile) {
if (!cycles.isEmpty()) {
for (Component.Builder component : builder.getComponents()) {
for (Cycle<Component> cycle : cycles) {
for (Cycle<IdentifiableComponent> cycle : cycles) {
if (contains(cycle, component.getName())) {
for (Component nodeInCycle : cycle.getNodes()) {
for (IdentifiableComponent nodeInCycle : cycle.getNodes()) {
if (component.getReads().containsKey(nodeInCycle.getName())) {
component.addRead(nodeInCycle.getName(), ReadKind.CYCLE);
}
Expand All @@ -230,8 +231,8 @@ public void onCompletingCompilation() {
}
}

private boolean contains(Cycle<Component> cycle, String name) {
for (Component component : cycle.getNodes()) {
private boolean contains(Cycle<IdentifiableComponent> cycle, String name) {
for (IdentifiableComponent component : cycle.getNodes()) {
if (component.getName().equals(name)) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.moditect.deptective.internal.log.DeptectiveMessages;
import org.moditect.deptective.internal.log.Log;
import org.moditect.deptective.internal.model.Component;
import org.moditect.deptective.internal.model.IdentifiableComponent;
import org.moditect.deptective.internal.model.PackageAssignedToMultipleComponentsException;
import org.moditect.deptective.internal.model.PackageDependencies;
import org.moditect.deptective.internal.model.ReadKind;
Expand Down Expand Up @@ -175,7 +176,7 @@ else if (currentComponent.allowedToRead(referencedComponent)) {
public void onCompletingCompilation() {
log.useSource(null);

List<Cycle<Component>> cycles = GraphUtils.detectCycles(allowedPackageDependencies.getComponents());
List<Cycle<IdentifiableComponent>> cycles = GraphUtils.detectCycles(allowedPackageDependencies.getComponents());

if (!cycles.isEmpty()) {
String cyclesAsString = "- " + cycles.stream()
Expand All @@ -191,9 +192,9 @@ public void onCompletingCompilation() {

if (!cycles.isEmpty()) {
for (Component.Builder component : actualPackageDependencies.getComponents()) {
for (Cycle<Component> cycle : cycles) {
for (Cycle<IdentifiableComponent> cycle : cycles) {
if (contains(cycle, component.getName())) {
for (Component nodeInCycle : cycle.getNodes()) {
for (IdentifiableComponent nodeInCycle : cycle.getNodes()) {
if (component.getReads().containsKey(nodeInCycle.getName())) {
component.addRead(nodeInCycle.getName(), ReadKind.CYCLE);
}
Expand All @@ -218,8 +219,8 @@ public void onCompletingCompilation() {
}
}

private boolean contains(Cycle<Component> cycle, String name) {
for (Component component : cycle.getNodes()) {
private boolean contains(Cycle<IdentifiableComponent> cycle, String name) {
for (IdentifiableComponent component : cycle.getNodes()) {
if (component.getName().equals(name)) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.Set;

import org.moditect.deptective.internal.graph.Dependency;
import org.moditect.deptective.internal.graph.Node;

/**
* Describes a component, a set of packages identified by one more naming patterns.
Expand All @@ -33,7 +32,7 @@
*
* @author Gunnar Morling
*/
public class Component implements Node<Component> {
public class Component extends IdentifiableComponent {

public static class Builder {

Expand Down Expand Up @@ -85,12 +84,11 @@ public String getName() {
}
}

private final String name;
private final Set<PackagePattern> contained;
private final Map<String, ReadKind> reads;

public Component(String name, Set<PackagePattern> contained, Map<String, ReadKind> reads) {
this.name = name;
super(name);
this.contained = Collections.unmodifiableSet(contained);
this.reads = Collections.unmodifiableMap(reads);
}
Expand All @@ -113,10 +111,6 @@ public boolean allowedToRead(Component other) {
return name.equals(other.name) || reads.get(other.getName()) == ReadKind.ALLOWED;
}

public String getName() {
return name;
}

public Set<PackagePattern> getContained() {
return contained;
}
Expand All @@ -136,11 +130,11 @@ public String asShortString() {
}

@Override
public Dependency<Component> getOutgoingDependencyTo(Component node) {
public Dependency<IdentifiableComponent> getOutgoingDependencyTo(IdentifiableComponent node) {
return reads.entrySet()
.stream()
.filter(e -> e.getKey().equals(node.getName()))
.map(e -> new Dependency<Component>(Component.builder(e.getKey()).build(), 1))
.map(e -> new Dependency<>(new ComponentReference(e.getKey()), 1))
.findFirst()
.orElse(null);
}
Expand All @@ -149,31 +143,4 @@ public Dependency<Component> getOutgoingDependencyTo(Component node) {
public boolean hasOutgoingDependencies() {
return !reads.isEmpty();
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Component other = (Component) obj;
if (name == null) {
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright 2019 The ModiTect authors
*
* 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.moditect.deptective.internal.model;

import org.moditect.deptective.internal.graph.Dependency;

/**
* A reference to a component.
*
* @author Gunnar Morling
*/
public class ComponentReference extends IdentifiableComponent {

public ComponentReference(String name) {
super(name);
}

@Override
public Dependency<IdentifiableComponent> getOutgoingDependencyTo(IdentifiableComponent node) {
throw new UnsupportedOperationException("No outgoing dependencies from reference");
}

@Override
public boolean hasOutgoingDependencies() {
return false;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Copyright 2019 The ModiTect authors
*
* 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.moditect.deptective.internal.model;

import org.moditect.deptective.internal.graph.Node;

/**
* A component in a software system, e.g. a package or a group of packages.
* <p>
* Identity and equality are solely based on the component's name.
*
* @author Gunnar Morling
*/
public abstract class IdentifiableComponent implements Node<IdentifiableComponent> {

protected final String name;

public IdentifiableComponent(String name) {
this.name = name;
}

public String getName() {
return name;
}

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

@Override
public final boolean equals(Object other) {
if (other instanceof IdentifiableComponent) {
return name.equals(((IdentifiableComponent) other).name);
}

return false;
}
}

0 comments on commit c73af1b

Please sign in to comment.