NoDuplicateRelationshipsListener.java
package org.thewonderlemming.c4plantuml.linter.rules.builtin;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.thewonderlemming.c4plantuml.commons.Reporter;
import org.thewonderlemming.c4plantuml.grammars.C4BaseListener;
import org.thewonderlemming.c4plantuml.grammars.SourceType;
import org.thewonderlemming.c4plantuml.grammars.generated.C4L1Parser;
import org.thewonderlemming.c4plantuml.grammars.generated.C4L2Parser;
import org.thewonderlemming.c4plantuml.grammars.generated.C4L3Parser;
/**
* An ANTLR 4 {@link ParseTreeListener} implementation that verifies that relationships are not declared more than once..
*
* @author thewonderlemming
*
*/
public class NoDuplicateRelationshipsListener extends C4BaseListener {
private static final String MESSAGE_FORMAT = "Duplicate relationship found for <'%s' -> '%s': '%s'>";
private final Set<String> declaredRelationShips = new HashSet<>();
private final Reporter reporter;
/**
* Default constructor.
*
* @param reporter {@link Reporter} instance to report to.
*/
public NoDuplicateRelationshipsListener(final Reporter reporter) {
this.reporter = reporter;
}
/**
* Collects the relationship definition in a {@link SourceType#C4_L1} grammar.
* <p>
* {@inheritDoc}
*/
@Override
public void enterRelationship(final C4L1Parser.RelationshipContext ctx) {
final List<TerminalNode> aliases = ctx.Alias();
final TerminalNode sourceAlias = aliases.get(0);
final TerminalNode targetAlias = aliases.get(1);
final TerminalNode label = ctx.String();
checkRelationshipIsUnique(sourceAlias, targetAlias, label);
}
/**
* Collects the relationship definition in a {@link SourceType#C4_L2} grammar.
* <p>
* {@inheritDoc}
*/
@Override
public void enterRelationship(final C4L2Parser.RelationshipContext ctx) {
final List<TerminalNode> aliases = ctx.Alias();
final TerminalNode sourceAlias = aliases.get(0);
final TerminalNode targetAlias = aliases.get(1);
final TerminalNode label = ctx.String(0);
checkRelationshipIsUnique(sourceAlias, targetAlias, label);
}
/**
* Collects the relationship definition in a {@link SourceType#C4_L3} grammar.
* <p>
* {@inheritDoc}
*/
@Override
public void enterRelationship(final C4L3Parser.RelationshipContext ctx) {
final List<TerminalNode> aliases = ctx.Alias();
final TerminalNode sourceAlias = aliases.get(0);
final TerminalNode targetAlias = aliases.get(1);
final TerminalNode label = ctx.String(0);
checkRelationshipIsUnique(sourceAlias, targetAlias, label);
}
private String buildErrorMessage(final TerminalNode sourceAlias, final TerminalNode targetAlias,
final TerminalNode label) {
return String.format(MESSAGE_FORMAT, sourceAlias.getText(), targetAlias.getText(), label.getText());
}
private void checkRelationshipIsUnique(final TerminalNode sourceAlias, final TerminalNode targetAlias,
final TerminalNode label) {
final String relationship = convertRelationshipToString(sourceAlias, targetAlias, label);
if (this.declaredRelationShips.contains(relationship)) {
final String errorMessage = buildErrorMessage(sourceAlias, targetAlias, label);
this.reporter.report(errorMessage);
} else {
this.declaredRelationShips.add(relationship);
}
}
private String convertRelationshipToString(final TerminalNode sourceAlias, final TerminalNode targetAlias,
final TerminalNode label) {
return sourceAlias.getText() + targetAlias.getText() + label.getText();
}
}