tool.designpatterns.verifiers.multiclassverifiers.compositeverifier.CompositeVerifier Maven / Gradle / Ivy
package tool.designpatterns.verifiers.multiclassverifiers.compositeverifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import tool.designpatterns.Pattern;
import tool.designpatterns.PatternGroup;
import tool.designpatterns.verifiers.IPatternGrouper;
import tool.designpatterns.verifiers.VerifierUtils;
import tool.feedback.Feedback;
import tool.feedback.FeedbackTrace;
import tool.feedback.FeedbackWrapper;
import tool.feedback.PatternGroupFeedback;
import tool.util.VariableReader;
/**
* A verifier for the compsite pattern.
*/
public class CompositeVerifier implements IPatternGrouper {
public CompositeVerifier() {
}
@Override
public PatternGroupFeedback verifyGroup(
Map> map) {
List patternInstances =
CompositePatternInstance.createInstancesFromMap(map);
List results = new ArrayList<>();
patternInstances.forEach(
patternInstance -> results.add(verifyPatternInstance(patternInstance)));
return new PatternGroupFeedback(PatternGroup.COMPOSITE, results);
}
/**
* Verifies one instance of the composite pattern.
*
* @param patternInstance a pattern instance
*
* @return a feedback
*/
public Feedback verifyPatternInstance(CompositePatternInstance patternInstance) {
Feedback allElementsFeedback = patternInstance.hasAllElements();
if (allElementsFeedback.getIsError()) {
return allElementsFeedback;
} else { // the instance is complete and the predicates may now be checked
List childFeedbacks = verifyPredicates(patternInstance);
return Feedback.getPatternInstanceFeedback(childFeedbacks);
}
}
/**
* This method checks all predicates and is only called if the PatternInstance.hasAllElements
* return true.
*
* @param patternInstance a complete pattern instance
*
* @return feedbacks
*/
private List verifyPredicates(CompositePatternInstance patternInstance) {
List feedbacks = new ArrayList<>();
feedbacks.add(componentHasMethods(patternInstance.getComponent()));
for (ClassOrInterfaceDeclaration container : patternInstance.getContainers()) {
FeedbackWrapper> collectionFields = getCollectionFieldsOfType(
container, patternInstance.getComponent());
if (collectionFields.getOther().isEmpty()) {
feedbacks.add(collectionFields.getFeedback());
} else {
feedbacks.add(delegatesToCollection(container, patternInstance.getComponent()));
}
}
return feedbacks;
}
/**
* Composite is defined by its delegate structure so if there are no methods which can delegate
* then it cannot be a composite.
*
* @param component the interface or abstract class defining the composite
*
* @return a feedback
*/
private Feedback componentHasMethods(ClassOrInterfaceDeclaration component) {
return VerifierUtils.hasAtLeastOnePublicMethod(component);
}
/**
* A container has to a have a field which extends from Collection with a type parameter the
* same as the Component.
*
* @param container the class which has to the specified field
* @param componentType define the type parameter of the collection.
*
* @return a feedback
*/
private FeedbackWrapper> getCollectionFieldsOfType(
ClassOrInterfaceDeclaration container, ClassOrInterfaceDeclaration componentType) {
List fieldNames = new ArrayList<>();
final String collectionType = "java.util.Collection";
for (FieldDeclaration field : VariableReader.readVariables(container)) {
for (ResolvedReferenceType type : field.getElementType().resolve().asReferenceType()
.getAllAncestors()) {
if (type.getQualifiedName().equals(collectionType)) {
for (var pair : type.getTypeParametersMap()) {
if (pair.b.describe().equals(componentType.getFullyQualifiedName().get())) {
fieldNames.add(field);
}
}
}
}
}
Feedback feedback;
if (fieldNames.isEmpty()) {
feedback = Feedback.getNoChildFeedback(
"The container has no Collection with the component as parameter",
new FeedbackTrace(container));
} else {
feedback = Feedback.getSuccessfulFeedback();
}
return new FeedbackWrapper<>(feedback, fieldNames);
}
/**
* Checks that a method delegates the call to at least one child of the type componentType.
*
* @param container The container that is being checked
* @param componentType The type of the children
*
* @return The result of the validation of the predicate
*/
private Feedback delegatesToCollection(
ClassOrInterfaceDeclaration container, ClassOrInterfaceDeclaration componentType) {
List responses = new ArrayList<>();
LoopVisitor looper = new LoopVisitor();
container.findAll(MethodDeclaration.class).forEach(methodInContainer -> {
if (VerifierUtils.methodBelongsToComponent(methodInContainer, componentType)) {
Feedback doesDelegateFeedback = methodInContainer.accept(looper, methodInContainer);
responses.add(doesDelegateFeedback);
responses.add(looper.hasIteratingBlock(methodInContainer));
looper.resetIteratingBlocks();
}
});
return Feedback.getFeedbackWithChildren(new FeedbackTrace(container), responses);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy