Skip to content

Commit

Permalink
Detect most provided interfaces weakly
Browse files Browse the repository at this point in the history
  • Loading branch information
FloBoJa committed Jan 19, 2024
1 parent 0c6dff8 commit d52e3f1
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ class JaxRSRules implements Rule {
}

for (iface : getAllInterfaces(unit)) {
pcmDetector.detectProvidedInterface(identifier, iface.resolveBinding)
pcmDetector.detectProvidedInterfaceWeakly(identifier, iface.resolveBinding)
for (m : getMethods(iface)) {
pcmDetector.detectProvidedOperation(identifier, iface.resolveBinding, m)
pcmDetector.detectProvidedOperationWeakly(identifier, iface.resolveBinding, m)
}
}
}
Expand All @@ -104,7 +104,7 @@ class JaxRSRules implements Rule {

pcmDetector.detectComponent(identifier)

getAllPublicMethods(unit).forEach[m|pcmDetector.detectProvidedOperation(identifier, m.resolveBinding)]
getAllPublicMethods(unit).forEach[m|pcmDetector.detectProvidedOperationWeakly(identifier, m.resolveBinding)]
// Do not detect requirements of services, this may connect them too tightly
if (!identifier.name.endsWith("ServiceImpl")) {
getFields(unit).forEach[f|pcmDetector.detectRequiredInterfaceWeakly(identifier, f)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ class SpringRules implements Rule {
val ifaceBinding = iface.resolveBinding
// Hide Repository interface implementations, they tend to connect composites in unrepresentative ways
if (ifaceBinding !== null && !ifaceBinding.name.endsWith("Repository")) {
pcmDetector.detectProvidedInterface(identifier, ifaceBinding)
pcmDetector.detectProvidedInterfaceWeakly(identifier, ifaceBinding)
for (m : getMethods(iface)) {
pcmDetector.detectProvidedOperation(identifier, ifaceBinding, m)
pcmDetector.detectProvidedOperationWeakly(identifier, ifaceBinding, m)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ private static Set<Component> collectConnectedComponents(final Set<Component> te
final Composite metaComposite = metaCompositeBuilder.construct(temporaryComponents,
new RequirementsBuilder().create(Set.of(), Set.of()), new ProvisionsBuilder().create(Set.of()),
Set.of());
return metaComposite.parts();
final Set<Component> connectedComponents = metaComposite.parts();
if (connectedComponents.isEmpty()) {
return temporaryComponents;
} else {
return connectedComponents;
}
}

private static Set<Component> createComponents(final Map<CompUnitOrName, ComponentBuilder> components,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,55 @@

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

public class ProvisionsBuilder {
private final List<OperationInterface> provisions = new LinkedList<>();
private final Set<OperationInterface> weakProvisions = new HashSet<>();

public void add(final OperationInterface... provisions) {
this.add(List.of(provisions));
}

public void add(final Collection<OperationInterface> provisions) {
public synchronized void add(final Collection<OperationInterface> provisions) {
this.provisions.addAll(provisions);
}

public synchronized void addWeakly(final OperationInterface iface) {
this.weakProvisions.add(iface);
}

public synchronized void strengthenIfPresent(final OperationInterface iface) {
if (this.weakProvisions.contains(iface)) {
this.weakProvisions.remove(iface);
this.provisions.add(iface);
}
}

public synchronized boolean containsRelated(final OperationInterface requirement) {
for (final OperationInterface provision : this.provisions) {
final boolean partlyProvided = provision.isPartOf(requirement);
final boolean entirelyProvided = requirement.isPartOf(provision);
if (partlyProvided || entirelyProvided) {
return true;
}
}

for (final OperationInterface provision : this.weakProvisions) {
final boolean partlyProvided = provision.isPartOf(requirement);
final boolean entirelyProvided = requirement.isPartOf(provision);
if (partlyProvided || entirelyProvided) {
return true;
}
}

return false;
}

public Provisions create(final Collection<OperationInterface> allDependencies) {
return new Provisions(this.provisions, allDependencies);
}
Expand All @@ -27,7 +61,7 @@ public List<OperationInterface> toList() {

@Override
public int hashCode() {
return Objects.hash(this.provisions);
return Objects.hash(this.provisions, this.weakProvisions);
}

@Override
Expand All @@ -39,6 +73,7 @@ public boolean equals(final Object obj) {
return false;
}
final ProvisionsBuilder other = (ProvisionsBuilder) obj;
return Objects.equals(this.provisions, other.provisions);
return Objects.equals(this.provisions, other.provisions)
&& Objects.equals(this.weakProvisions, other.weakProvisions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,41 @@ public void add(final OperationInterface... interfaces) {
this.add(List.of(interfaces));
}

public void add(final Collection<OperationInterface> interfaces) {
public synchronized void add(final Collection<OperationInterface> interfaces) {
this.requirements.addAll(interfaces);
}

public void addWeakly(final OperationInterface iface) {
public synchronized void addWeakly(final OperationInterface iface) {
this.weakRequirements.add(iface);
}

public void strengthenIfPresent(final OperationInterface iface) {
public synchronized void strengthenIfPresent(final OperationInterface iface) {
if (this.weakRequirements.contains(iface)) {
this.weakRequirements.remove(iface);
this.requirements.add(iface);
}
}

public synchronized boolean containsRelated(OperationInterface provision) {
for (final OperationInterface requirement : this.requirements) {
final boolean partlyRequired = requirement.isPartOf(provision);
final boolean entirelyRequired = provision.isPartOf(requirement);
if (partlyRequired || entirelyRequired) {
return true;
}
}

for (final OperationInterface requirement : this.weakRequirements) {
final boolean partlyRequired = requirement.isPartOf(provision);
final boolean entirelyRequired = provision.isPartOf(requirement);
if (partlyRequired || entirelyRequired) {
return true;
}
}

return false;
}

public Requirements create(final Collection<OperationInterface> allDependencies,
final Collection<OperationInterface> visibleProvisions) {
return new Requirements(this.requirements, allDependencies, visibleProvisions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -45,7 +44,6 @@ public class PCMDetector {
private final Map<String, CompositeBuilder> composites = new ConcurrentHashMap<>();
private final ProvisionsBuilder compositeProvisions = new ProvisionsBuilder();
private final RequirementsBuilder compositeRequirements = new RequirementsBuilder();
private final Set<OperationInterface> providedInterfaces = new HashSet<>();

private static String getFullUnitName(final CompUnitOrName unit) {
// TODO this is potentially problematic, maybe restructure
Expand Down Expand Up @@ -92,7 +90,7 @@ public void detectComponent(final CompUnitOrName unit) {
if (type instanceof TypeDeclaration) {
this.components.put(unit, new ComponentBuilder(unit));
final ITypeBinding binding = ((TypeDeclaration) type).resolveBinding();
this.detectProvidedInterface(unit, binding);
this.detectProvidedInterfaceWeakly(unit, binding);
}
}
}
Expand Down Expand Up @@ -162,7 +160,11 @@ private void detectRequiredInterface(final CompUnitOrName unit, final boolean co
private void detectRequiredInterface(final CompUnitOrName unit, final boolean compositeRequired,
final boolean detectWeakly, final Collection<OperationInterface> ifaces) {
for (final OperationInterface iface : ifaces) {
if (detectWeakly && !this.providedInterfaces.contains(iface)) {
final boolean isProvided = this.compositeProvisions.containsRelated(iface) || this.components.values()
.stream()
.anyMatch(component -> component.provisions()
.containsRelated(iface));
if (!isProvided && detectWeakly) {
this.components.get(unit)
.requirements()
.addWeakly(iface);
Expand All @@ -173,6 +175,11 @@ private void detectRequiredInterface(final CompUnitOrName unit, final boolean co
this.components.get(unit)
.requirements()
.add(iface);
this.components.values()
.stream()
.forEach(component -> component.provisions()
.strengthenIfPresent(iface));
this.compositeProvisions.strengthenIfPresent(iface);
if (compositeRequired) {
this.compositeRequirements.add(iface);
}
Expand All @@ -181,34 +188,67 @@ private void detectRequiredInterface(final CompUnitOrName unit, final boolean co
}

public void detectProvidedInterface(final CompUnitOrName unit, final ITypeBinding iface) {
this.detectProvidedInterface(unit, iface, false, false);
}

public void detectProvidedInterfaceWeakly(final CompUnitOrName unit, final ITypeBinding iface) {
this.detectProvidedInterface(unit, iface, false, true);
}

private void detectProvidedInterface(final CompUnitOrName unit, final ITypeBinding iface,
final boolean compositeProvided, final boolean detectWeakly) {
if (iface == null) {
LOG.warn("Unresolved type binding detected in " + getFullUnitName(unit) + "!");
return;
}
final OperationInterface provision = new EntireInterface(iface,
new JavaInterfaceName(NameConverter.toPCMIdentifier(iface)));
this.detectProvidedInterface(unit, provision);
this.detectProvidedInterface(unit, provision, compositeProvided, detectWeakly);
}

public void detectProvidedOperation(final CompUnitOrName unit, final IMethodBinding method) {
detectProvidedOperation(unit, method, false);
}

public void detectProvidedOperationWeakly(final CompUnitOrName unit, final IMethodBinding method) {
detectProvidedOperation(unit, method, true);
}

private void detectProvidedOperation(final CompUnitOrName unit, final IMethodBinding method,
final boolean detectWeakly) {
if (method == null) {
LOG.warn("Unresolved method binding detected in " + getFullUnitName(unit) + "!");
return;
}
this.detectProvidedOperation(unit, method.getDeclaringClass(), method);
this.detectProvidedOperation(unit, method.getDeclaringClass(), method, detectWeakly);
}

public void detectProvidedOperation(final CompUnitOrName unit, final ITypeBinding declaringIface,
final IMethodBinding method) {
this.detectProvidedOperation(unit, declaringIface, method, false);
}

public void detectProvidedOperationWeakly(final CompUnitOrName unit, final ITypeBinding declaringIface,
final IMethodBinding method) {
this.detectProvidedOperation(unit, declaringIface, method, true);
}

private void detectProvidedOperation(final CompUnitOrName unit, final ITypeBinding declaringIface,
final IMethodBinding method, final boolean detectWeakly) {
if (declaringIface == null) {
LOG.warn("Unresolved type binding detected in " + getFullUnitName(unit) + "!");
return;
}
this.detectProvidedOperation(unit, NameConverter.toPCMIdentifier(declaringIface), method);
this.detectProvidedOperation(unit, NameConverter.toPCMIdentifier(declaringIface), method, false, detectWeakly);
}

public void detectProvidedOperation(final CompUnitOrName unit, final String declaringIface,
final IMethodBinding method) {
this.detectProvidedOperation(unit, declaringIface, method, false, false);
}

private void detectProvidedOperation(final CompUnitOrName unit, final String declaringIface,
final IMethodBinding method, final boolean compositeProvided, final boolean detectWeakly) {
String operationName;
if (method == null) {
LOG.warn("Unresolved method binding detected in " + getFullUnitName(unit) + "!");
Expand All @@ -217,27 +257,57 @@ public void detectProvidedOperation(final CompUnitOrName unit, final String decl
operationName = method.getName();
}

this.detectProvidedOperation(unit, method, new JavaOperationName(declaringIface, operationName));
this.detectProvidedOperation(unit, method, new JavaOperationName(declaringIface, operationName),
compositeProvided, detectWeakly);
}

public void detectProvidedOperation(final CompUnitOrName unit, final IMethodBinding method,
final OperationName name) {
detectProvidedOperation(unit, method, name, false, false);
}

private void detectProvidedOperation(final CompUnitOrName unit, final IMethodBinding method,
final OperationName name, final boolean compositeProvided, final boolean detectWeakly) {
if (this.components.get(unit) == null) {
this.components.put(unit, new ComponentBuilder(unit));
}
final OperationInterface provision = new Operation(method, name);
this.detectProvidedInterface(unit, provision);
this.detectProvidedInterface(unit, provision, compositeProvided, detectWeakly);
}

public void detectProvidedInterface(final CompUnitOrName unit, final OperationInterface provision) {
this.components.get(unit)
.provisions()
.add(provision);
this.providedInterfaces.add(provision);
this.components.values()
.stream()
.forEach(component -> component.requirements()
.strengthenIfPresent(provision));
private void detectProvidedInterface(final CompUnitOrName unit, final OperationInterface iface,
final boolean compositeProvided, final boolean detectWeakly) {
this.detectProvidedInterface(unit, compositeProvided, detectWeakly, List.of(iface));
}

private void detectProvidedInterface(final CompUnitOrName unit, final boolean compositeProvided,
final boolean detectWeakly, final Collection<OperationInterface> ifaces) {
for (final OperationInterface iface : ifaces) {
final boolean isRequired = this.compositeRequirements.containsRelated(iface) || this.components.values()
.stream()
.anyMatch(component -> component.requirements()
.containsRelated(iface));
if (!isRequired && detectWeakly) {
this.components.get(unit)
.provisions()
.addWeakly(iface);
if (compositeProvided) {
this.compositeProvisions.addWeakly(iface);
}
} else {
this.components.get(unit)
.provisions()
.add(iface);
this.components.values()
.stream()
.forEach(component -> component.requirements()
.strengthenIfPresent(iface));
this.compositeRequirements.strengthenIfPresent(iface);
if (compositeProvided) {
this.compositeProvisions.add(iface);
}
}
}
}

public void detectPartOfComposite(final CompUnitOrName unit, final String compositeName) {
Expand Down Expand Up @@ -266,19 +336,17 @@ public void detectCompositeProvidedOperation(final CompUnitOrName unit, final IM

public void detectCompositeProvidedOperation(final CompUnitOrName unit, final ITypeBinding declaringIface,
final IMethodBinding method) {
this.detectCompositeProvidedOperation(unit, NameConverter.toPCMIdentifier(declaringIface), method);
this.detectCompositeProvidedOperation(unit, NameConverter.toPCMIdentifier(declaringIface), method, false);
}

public void detectCompositeProvidedOperation(final CompUnitOrName unit, final String declaringIface,
final IMethodBinding method) {
this.compositeProvisions.add(new Operation(method, new JavaOperationName(declaringIface, method.getName())));
this.detectProvidedOperation(unit, declaringIface, method);
private void detectCompositeProvidedOperation(final CompUnitOrName unit, final String declaringIface,
final IMethodBinding method, final boolean detectWeakly) {
this.detectProvidedOperation(unit, declaringIface, method, true, detectWeakly);
}

public void detectCompositeProvidedOperation(final CompUnitOrName unit, final IMethodBinding method,
final OperationName name) {
this.compositeProvisions.add(new Operation(method, name));
this.detectProvidedOperation(unit, method, name);
this.detectProvidedOperation(unit, method, name, true, false);
}

private CompositeBuilder getComposite(final String name) {
Expand Down

0 comments on commit d52e3f1

Please sign in to comment.