From 3cf9b5ec97d581ea883e7fad5d565ad0c018eb82 Mon Sep 17 00:00:00 2001 From: Florian Bossert Date: Sat, 13 Jul 2024 21:37:47 +0200 Subject: [PATCH 1/3] Add TeaStore rules --- .../plugin.xml | 8 +++ .../discoverers/DockerfileDiscoverer.java | 69 +++++++++++++++++++ .../plugin.xml | 8 +++ .../extraction/rules/TeaStoreRules.xtend | 66 ++++++++++++++++++ .../extraction/commonalities/Component.java | 10 ++- .../commonalities/ComponentBuilder.java | 9 ++- .../commonalities/CompositeBuilder.java | 13 ++++ .../extraction/engine/PCMDetector.java | 17 +++++ 8 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 bundles/org.palladiosimulator.retriever.extraction.discoverers/src/org/palladiosimulator/retriever/extraction/discoverers/DockerfileDiscoverer.java create mode 100644 bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend diff --git a/bundles/org.palladiosimulator.retriever.extraction.discoverers/plugin.xml b/bundles/org.palladiosimulator.retriever.extraction.discoverers/plugin.xml index 71c3e256..1df443ee 100644 --- a/bundles/org.palladiosimulator.retriever.extraction.discoverers/plugin.xml +++ b/bundles/org.palladiosimulator.retriever.extraction.discoverers/plugin.xml @@ -57,5 +57,13 @@ class="org.palladiosimulator.retriever.extraction.discoverers.EcmaScriptDiscoverer"> + + + + diff --git a/bundles/org.palladiosimulator.retriever.extraction.discoverers/src/org/palladiosimulator/retriever/extraction/discoverers/DockerfileDiscoverer.java b/bundles/org.palladiosimulator.retriever.extraction.discoverers/src/org/palladiosimulator/retriever/extraction/discoverers/DockerfileDiscoverer.java new file mode 100644 index 00000000..6ed08c3d --- /dev/null +++ b/bundles/org.palladiosimulator.retriever.extraction.discoverers/src/org/palladiosimulator/retriever/extraction/discoverers/DockerfileDiscoverer.java @@ -0,0 +1,69 @@ +package org.palladiosimulator.retriever.extraction.discoverers; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.common.CommonPlugin; +import org.palladiosimulator.retriever.services.Discoverer; +import org.palladiosimulator.retriever.services.RetrieverConfiguration; +import org.palladiosimulator.retriever.services.blackboard.RetrieverBlackboard; + +import de.uka.ipd.sdq.workflow.jobs.AbstractBlackboardInteractingJob; +import de.uka.ipd.sdq.workflow.jobs.CleanupFailedException; +import de.uka.ipd.sdq.workflow.jobs.IBlackboardInteractingJob; +import de.uka.ipd.sdq.workflow.jobs.JobFailedException; +import de.uka.ipd.sdq.workflow.jobs.UserCanceledException; + +public class DockerfileDiscoverer implements Discoverer { + + private static final String DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.docker"; + + @Override + public IBlackboardInteractingJob create(final RetrieverConfiguration configuration, + final RetrieverBlackboard blackboard) { + return new AbstractBlackboardInteractingJob<>() { + + @Override + public void cleanup(final IProgressMonitor monitor) throws CleanupFailedException { + } + + @Override + public void execute(final IProgressMonitor monitor) throws JobFailedException, UserCanceledException { + final Path root = Paths.get(CommonPlugin.asLocalURI(configuration.getInputFolder()) + .devicePath()); + this.setBlackboard(Objects.requireNonNull(blackboard)); + final Map dockerfiles = new HashMap<>(); + Discoverer.find(root, "Dockerfile", this.logger) + .forEach(p -> dockerfiles.put(p, null)); + this.getBlackboard() + .putDiscoveredFiles(DISCOVERER_ID, dockerfiles); + } + + @Override + public String getName() { + return "Dockerfile Discoverer Job"; + } + }; + } + + @Override + public Set getConfigurationKeys() { + return Collections.emptySet(); + } + + @Override + public String getID() { + return DISCOVERER_ID; + } + + @Override + public String getName() { + return "Dockerfile Discoverer"; + } +} diff --git a/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml b/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml index e2b31a2d..a77897eb 100644 --- a/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml +++ b/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml @@ -81,5 +81,13 @@ class="org.palladiosimulator.retriever.extraction.rules.JaxRSDeploymentRules"> + + + + diff --git a/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend b/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend new file mode 100644 index 00000000..1e356936 --- /dev/null +++ b/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend @@ -0,0 +1,66 @@ +package org.palladiosimulator.retriever.extraction.rules + +import java.nio.file.Path; +import java.util.HashSet +import org.eclipse.jdt.core.dom.CompilationUnit +import java.util.Set +import org.palladiosimulator.retriever.services.blackboard.RetrieverBlackboard +import org.palladiosimulator.retriever.services.Rule +import org.palladiosimulator.retriever.extraction.engine.PCMDetector +import org.palladiosimulator.retriever.extraction.commonalities.CompUnitOrName + +class TeaStoreRules implements Rule { + + static final String RULE_ID = "org.palladiosimulator.retriever.extraction.rules.teastore" + static final String JAVA_DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.java"; + static final String DOCKER_DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.docker"; + static final String DOCKER_FILE_NAME = "Dockerfile"; + + override processRules(RetrieverBlackboard blackboard, Path path) { + if (path !== null && path.fileName.toString().equals(DOCKER_FILE_NAME)) { + val parentName = path.parent.fileName.toString() + + // Add all file system children as associated compilation units + var children = new HashSet(); + var parentPath = path.parent; + for (entry : blackboard.getDiscoveredFiles(JAVA_DISCOVERER_ID, typeof(CompilationUnit)).entrySet) { + if (entry.key.startsWith(parentPath)) { + children.add(entry.value); + } + } + val pcmDetector = blackboard.PCMDetector as PCMDetector; + for (unit : children) { + if (pcmDetector.compilationUnits.contains(new CompUnitOrName(unit))) { + pcmDetector.detectSeparatingIdentifier(new CompUnitOrName(unit), parentName) + if (pcmDetector.isPartOfComposite(new CompUnitOrName(unit))) { + pcmDetector.detectPartOfComposite(new CompUnitOrName(unit), parentName) + } + } + } + } + } + + override isBuildRule() { + return true + } + + override getConfigurationKeys() { + return Set.of + } + + override getID() { + return RULE_ID + } + + override getName() { + return "TeaStore Rules" + } + + override getRequiredServices() { + return Set.of(JAVA_DISCOVERER_ID, DOCKER_DISCOVERER_ID) + } + + override getDependentServices() { + Set.of + } +} diff --git a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/Component.java b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/Component.java index a45035f8..e44e390a 100644 --- a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/Component.java +++ b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/Component.java @@ -15,12 +15,14 @@ public class Component { private final CompUnitOrName compUnitOrName; private final Requirements requirements; private final Provisions provisions; + private final Optional separatingIdentifier; - public Component(final CompUnitOrName compUnitOrName, final Requirements requirements, - final Provisions provisions) { + public Component(final CompUnitOrName compUnitOrName, final Requirements requirements, final Provisions provisions, + final Optional separatingIdentifier) { this.compUnitOrName = compUnitOrName; this.requirements = requirements; this.provisions = provisions; + this.separatingIdentifier = separatingIdentifier; } public Requirements requirements() { @@ -43,6 +45,10 @@ public CompUnitOrName identifier() { return this.compUnitOrName; } + public Optional separatingIdentifier() { + return this.separatingIdentifier; + } + @Override public int hashCode() { return Objects.hash(this.compUnitOrName, this.provisions, this.requirements); diff --git a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/ComponentBuilder.java b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/ComponentBuilder.java index 41fa93d9..98d3f4d7 100644 --- a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/ComponentBuilder.java +++ b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/ComponentBuilder.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.Objects; +import java.util.Optional; /** * Used to build {@code Component}s. @@ -13,11 +14,13 @@ public class ComponentBuilder { private final CompUnitOrName compUnitOrName; private final RequirementsBuilder requirements; private final ProvisionsBuilder provisions; + private Optional separatingIdentifier; public ComponentBuilder(final CompUnitOrName compUnitOrName) { this.compUnitOrName = compUnitOrName; this.requirements = new RequirementsBuilder(); this.provisions = new ProvisionsBuilder(); + this.separatingIdentifier = Optional.empty(); } public CompUnitOrName identifier() { @@ -32,10 +35,14 @@ public ProvisionsBuilder provisions() { return this.provisions; } + public void setSeparatingIdentifier(final String separatingIdentifier) { + this.separatingIdentifier = Optional.of(separatingIdentifier); + } + public Component create(final Collection allDependencies, final Collection visibleProvisions) { return new Component(this.compUnitOrName, this.requirements.create(allDependencies, visibleProvisions), - this.provisions.create(allDependencies)); + this.provisions.create(allDependencies), this.separatingIdentifier); } @Override diff --git a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/CompositeBuilder.java b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/CompositeBuilder.java index cf14eea0..fcc47ceb 100644 --- a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/CompositeBuilder.java +++ b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/CompositeBuilder.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.PriorityQueue; import java.util.Queue; import java.util.Set; @@ -215,6 +216,8 @@ private static List findRequiringComponents(final Set !compositeProvisions.containsEntire(x)) .forEach(provisions::add); + final Optional separatingIdentifier = providingComponent.separatingIdentifier(); + final List traversedOperations = new ArrayList<>(); while (!provisions.isEmpty()) { final OperationInterface provision = provisions.pop(); @@ -222,6 +225,10 @@ private static List findRequiringComponents(final Set x.requirements() .containsPartOf(provision)) .filter(x -> !providingComponent.equals(x)) + .filter(x -> x.separatingIdentifier() + .isEmpty() || separatingIdentifier.isEmpty() + || x.separatingIdentifier() + .equals(separatingIdentifier)) .collect(Collectors.toSet()); // Skip this provision if no unit requires it. @@ -250,6 +257,8 @@ private static List findProvidingComponents(final Set !compositeProvisions.containsEntire(x)) .forEach(requirements::add); + final Optional separatingIdentifier = requiringComponent.separatingIdentifier(); + final List traversedOperations = new ArrayList<>(); while (!requirements.isEmpty()) { final OperationInterface requirement = requirements.pop(); @@ -257,6 +266,10 @@ private static List findProvidingComponents(final Set x.provisions() .containsPartOf(requirement)) .filter(x -> !requiringComponent.equals(x)) + .filter(x -> x.separatingIdentifier() + .isEmpty() || separatingIdentifier.isEmpty() + || x.separatingIdentifier() + .equals(separatingIdentifier)) .collect(Collectors.toSet()); // Skip this requirement if no unit provides it. diff --git a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java index 1002d9b3..658d06bf 100644 --- a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java +++ b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java @@ -259,6 +259,14 @@ private void detectProvidedInterface(final CompUnitOrName unit, final OperationI } } + public void detectSeparatingIdentifier(final CompUnitOrName unit, final String separatingIdentifier) { + if (this.components.get(unit) == null) { + this.components.put(unit, new ComponentBuilder(unit)); + } + this.components.get(unit) + .setSeparatingIdentifier(separatingIdentifier); + } + public void detectPartOfComposite(final CompUnitOrName unit, final String compositeName) { if (this.components.get(unit) == null) { this.components.put(unit, new ComponentBuilder(unit)); @@ -302,4 +310,13 @@ public String toString() { }); return sb.toString(); } + + public boolean isPartOfComposite(CompUnitOrName name) { + for (CompositeBuilder composite : this.composites.values()) { + if (composite.hasPart(name)) { + return true; + } + } + return false; + } } From 5f42c78cff807116470163707fd92b24fe610c05 Mon Sep 17 00:00:00 2001 From: Florian Bossert Date: Mon, 29 Jul 2024 09:02:28 +0200 Subject: [PATCH 2/3] Add API for TeaStoreRules and add more project-specific logic --- .../extraction/rules/TeaStoreRules.xtend | 84 ++++++++++++++++--- .../commonalities/PCMDetectionResult.java | 57 ++++++++++--- .../extraction/engine/PCMDetector.java | 71 ++++++++++++++-- 3 files changed, 186 insertions(+), 26 deletions(-) diff --git a/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend b/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend index 1e356936..c1efcc25 100644 --- a/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend +++ b/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend @@ -8,40 +8,102 @@ import org.palladiosimulator.retriever.services.blackboard.RetrieverBlackboard import org.palladiosimulator.retriever.services.Rule import org.palladiosimulator.retriever.extraction.engine.PCMDetector import org.palladiosimulator.retriever.extraction.commonalities.CompUnitOrName +import java.util.Map +import static org.palladiosimulator.retriever.extraction.engine.RuleHelper.* +import org.eclipse.jdt.core.dom.ASTVisitor +import org.eclipse.jdt.core.dom.ExpressionStatement +import org.eclipse.jdt.core.dom.MethodInvocation +import org.palladiosimulator.retriever.extraction.commonalities.RESTOperationName +import org.palladiosimulator.retriever.extraction.commonalities.RESTName class TeaStoreRules implements Rule { static final String RULE_ID = "org.palladiosimulator.retriever.extraction.rules.teastore" static final String JAVA_DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.java"; static final String DOCKER_DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.docker"; + static final String JAX_RS_RULE_ID = "org.palladiosimulator.retriever.extraction.rules.jax_rs"; + static final String JAX_RS_DEPLOYMENT_RULE_ID = "org.palladiosimulator.retriever.extraction.rules.jax_rs.deployment"; static final String DOCKER_FILE_NAME = "Dockerfile"; override processRules(RetrieverBlackboard blackboard, Path path) { - if (path !== null && path.fileName.toString().equals(DOCKER_FILE_NAME)) { + if (path === null) { + return + } + + val compilationUnits = blackboard.getDiscoveredFiles(JAVA_DISCOVERER_ID, typeof(CompilationUnit)); + val pcmDetector = blackboard.PCMDetector as PCMDetector; + + if (path.fileName.toString().equals(DOCKER_FILE_NAME)) { val parentName = path.parent.fileName.toString() // Add all file system children as associated compilation units var children = new HashSet(); var parentPath = path.parent; - for (entry : blackboard.getDiscoveredFiles(JAVA_DISCOVERER_ID, typeof(CompilationUnit)).entrySet) { + for (entry : compilationUnits.entrySet) { if (entry.key.startsWith(parentPath)) { children.add(entry.value); } } - val pcmDetector = blackboard.PCMDetector as PCMDetector; for (unit : children) { - if (pcmDetector.compilationUnits.contains(new CompUnitOrName(unit))) { - pcmDetector.detectSeparatingIdentifier(new CompUnitOrName(unit), parentName) - if (pcmDetector.isPartOfComposite(new CompUnitOrName(unit))) { - pcmDetector.detectPartOfComposite(new CompUnitOrName(unit), parentName) - } + pcmDetector.detectSeparatingIdentifier(new CompUnitOrName(unit), parentName) + pcmDetector.detectPartOfWeakComposite(new CompUnitOrName(unit), parentName) + } + + val hostnameMap = blackboard.getPartition(JAX_RS_DEPLOYMENT_RULE_ID) as Map + var hasHostnamePath = false + for (hostnamePath : hostnameMap.keySet) { + if (hostnamePath !== null && path.startsWith(hostnamePath)) { + hasHostnamePath = true } } + if (!hasHostnamePath) { + hostnameMap.put(path.parent, parentName) + } + } + + if (compilationUnits.containsKey(path)) { + val unit = compilationUnits.get(path) + val identifier = new CompUnitOrName(unit) + if (identifier.name().endsWith("Startup") && !identifier.name.endsWith("LogReaderStartup")) { + // Make Startup components part of a composite so that they become part of the weak Dockerfile composite + pcmDetector.detectPartOfComposite(identifier, identifier.name() + "_tempComposite") + val contextInitializedMethod = getMethods(unit).stream().filter[m|m.name.fullyQualifiedName.endsWith("contextInitialized")].findFirst() + if (contextInitializedMethod.present) { + contextInitializedMethod.get.accept(new TeaStoreASTVisitor(identifier, pcmDetector)); + } + } else if (identifier.name().endsWith("ServiceLoadBalancer")) { + pcmDetector.detectComponent(identifier) + } else if (identifier.name().endsWith("RegistryClient")) { + pcmDetector.detectComponent(identifier) + pcmDetector.detectRequiredInterface(identifier, new RESTName("tools.descartes.teastore.registry", "/services")) + } + } + } + + static class TeaStoreASTVisitor extends ASTVisitor { + CompUnitOrName identifier; + PCMDetector pcmDetector; + + new(CompUnitOrName identifier, PCMDetector pcmDetector) { + this.identifier = identifier; + this.pcmDetector = pcmDetector + } + + override visit(ExpressionStatement statement) { + if (!(statement.expression instanceof MethodInvocation)) { + return true + } + + val invocation = statement.expression as MethodInvocation + // TODO: avoid self-references + pcmDetector.detectCompositeRequiredInterfaceWeakly(identifier, invocation) + + return true } } override isBuildRule() { - return true + return false } override getConfigurationKeys() { @@ -57,10 +119,10 @@ class TeaStoreRules implements Rule { } override getRequiredServices() { - return Set.of(JAVA_DISCOVERER_ID, DOCKER_DISCOVERER_ID) + return Set.of(JAVA_DISCOVERER_ID, DOCKER_DISCOVERER_ID, JAX_RS_DEPLOYMENT_RULE_ID) } override getDependentServices() { - Set.of + Set.of(JAX_RS_RULE_ID) } } diff --git a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/PCMDetectionResult.java b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/PCMDetectionResult.java index 0cd38553..208c3f8c 100644 --- a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/PCMDetectionResult.java +++ b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/commonalities/PCMDetectionResult.java @@ -4,6 +4,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -93,19 +94,16 @@ private static Set createCompositeComponents(final Set fre final Set redundantComposites = new HashSet<>(); final Set remainingComposites = new HashSet<>(); - for (int i = 0; i < allComposites.size(); ++i) { - final Composite subject = allComposites.get(i); - final long subsetCount = allComposites.subList(i + 1, allComposites.size()) - .stream() + for (final Composite subject : allComposites) { + final Optional other = allComposites.stream() + .filter(x -> !subject.equals(x)) .filter(x -> !redundantComposites.contains(x)) - .filter(x -> subject.isSubsetOf(x) || x.isSubsetOf(subject)) - .count(); + .filter(x -> subject.isSubsetOf(x)) + .findFirst(); - // Any composite is guaranteed to be the subset of at least one composite in the - // list, namely itself. If it is the subset of any composites other than itself, it is - // redundant. - if (subsetCount > 0) { + if (other.isPresent()) { redundantComposites.add(subject); + continue; } else { // TODO: Is there any merging necessary, like adapting the redundant composite's // requirements to its peer? @@ -113,7 +111,46 @@ private static Set createCompositeComponents(final Set fre } } + // Remove composite components contained in multiple other composites, according to a + // conservative heuristic. + // TODO: A comprehensive solution would require e.g. graph traversal and tie-breaking in + // cycles. + + final Set collectivelyContainedComposites = new HashSet<>(); + for (final Composite subject : remainingComposites) { + final Set allOtherParts = remainingComposites.stream() + .filter(x -> !subject.equals(x)) + .map(Composite::parts) + .flatMap(Set::stream) + .collect(Collectors.toSet()); + final boolean isContainedInOthers = subject.parts() + .stream() + .allMatch(allOtherParts::contains); + if (isContainedInOthers) { + collectivelyContainedComposites.add(subject); + } + } + + final Set actuallyContainedComposites = new HashSet<>(); + for (final Composite subject : collectivelyContainedComposites) { + final Set allOtherParts = remainingComposites.stream() + .filter(x -> !subject.equals(x)) + .filter(x -> !collectivelyContainedComposites.contains(x)) + .map(Composite::parts) + .flatMap(Set::stream) + .collect(Collectors.toSet()); + final boolean isContainedInOthers = subject.parts() + .stream() + .allMatch(allOtherParts::contains); + if (isContainedInOthers) { + actuallyContainedComposites.add(subject); + } + } + + remainingComposites.removeAll(actuallyContainedComposites); + return remainingComposites; + } private static Set collectVisibleProvisions(final Set components, diff --git a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java index 658d06bf..14949878 100644 --- a/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java +++ b/bundles/org.palladiosimulator.retriever.extraction/src/org/palladiosimulator/retriever/extraction/engine/PCMDetector.java @@ -14,6 +14,7 @@ import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclaration; @@ -44,6 +45,8 @@ public class PCMDetector { private final Map composites = new ConcurrentHashMap<>(); private final ProvisionsBuilder compositeProvisions = new ProvisionsBuilder(); private final RequirementsBuilder compositeRequirements = new RequirementsBuilder(); + private final Map> weakComponents = new ConcurrentHashMap<>(); + private final Map separatingIdentifiers = new ConcurrentHashMap<>(); private static String getFullUnitName(final CompUnitOrName unit) { // TODO this is potentially problematic, maybe restructure @@ -73,14 +76,18 @@ private static String getFullUnitName(final CompUnitOrName unit) { public void detectComponent(final CompUnitOrName unit) { if (!unit.isUnit()) { - this.components.put(unit, new ComponentBuilder(unit)); + if (this.components.get(unit) == null) { + this.components.put(unit, new ComponentBuilder(unit)); + } return; } for (final Object type : unit.compilationUnit() .get() .types()) { if (type instanceof TypeDeclaration) { - this.components.put(unit, new ComponentBuilder(unit)); + if (this.components.get(unit) == null) { + this.components.put(unit, new ComponentBuilder(unit)); + } final ITypeBinding binding = ((TypeDeclaration) type).resolveBinding(); this.detectProvidedInterfaceWeakly(unit, binding); } @@ -123,6 +130,20 @@ private void detectRequiredInterface(final CompUnitOrName unit, final FieldDecla this.detectRequired(unit, compositeRequired, detectWeakly, ifaces); } + public void detectCompositeRequiredInterfaceWeakly(final CompUnitOrName unit, final MethodInvocation invocation) { + final IMethodBinding method = invocation.resolveMethodBinding(); + if (method == null) { + return; + } + final ITypeBinding type = method.getDeclaringClass(); + if (this.components.get(unit) == null) { + this.components.put(unit, new ComponentBuilder(unit)); + } + final EntireInterface iface = new EntireInterface(type, + new JavaInterfaceName(NameConverter.toPCMIdentifier(type))); + this.detectRequiredInterface(unit, true, true, iface); + } + public void detectRequiredInterface(final CompUnitOrName unit, final SingleVariableDeclaration parameter) { if (this.components.get(unit) == null) { this.components.put(unit, new ComponentBuilder(unit)); @@ -261,10 +282,11 @@ private void detectProvidedInterface(final CompUnitOrName unit, final OperationI public void detectSeparatingIdentifier(final CompUnitOrName unit, final String separatingIdentifier) { if (this.components.get(unit) == null) { - this.components.put(unit, new ComponentBuilder(unit)); + this.separatingIdentifiers.put(unit, separatingIdentifier); + } else { + this.components.get(unit) + .setSeparatingIdentifier(separatingIdentifier); } - this.components.get(unit) - .setSeparatingIdentifier(separatingIdentifier); } public void detectPartOfComposite(final CompUnitOrName unit, final String compositeName) { @@ -276,6 +298,45 @@ public void detectPartOfComposite(final CompUnitOrName unit, final String compos } this.composites.get(compositeName) .addPart(this.components.get(unit)); + + // Setting the separating identifier is sufficient if the component is part of a composite + if (separatingIdentifiers.containsKey(unit)) { + this.components.get(unit) + .setSeparatingIdentifier(separatingIdentifiers.get(unit)); + } + + // Realize weak composite components that this component is part of + if (this.weakComponents.containsKey(unit)) { + for (String weakCompositeName : weakComponents.get(unit)) { + if (!this.composites.containsKey(weakCompositeName)) { + this.composites.put(weakCompositeName, new CompositeBuilder(weakCompositeName)); + } + this.composites.get(weakCompositeName) + .addPart(this.components.get(unit)); + } + } + } + + // Weak composite components only get created if at least one of their components is part of + // another composite. This allows for e.g. composite components based on build files that + // do not require direct dependencies between their parts. + public void detectPartOfWeakComposite(CompUnitOrName unit, String compositeName) { + if (!this.weakComponents.containsKey(unit)) { + this.weakComponents.put(unit, new ArrayList<>()); + } + this.weakComponents.get(unit) + .add(compositeName); + + final boolean isPartOfStrongComposite = this.composites.values() + .stream() + .anyMatch(x -> x.hasPart(unit)); + if (isPartOfStrongComposite) { + if (!this.composites.containsKey(compositeName)) { + this.composites.put(compositeName, new CompositeBuilder(compositeName)); + } + this.composites.get(compositeName) + .addPart(this.components.get(unit)); + } } public void detectCompositeRequiredInterface(final CompUnitOrName unit, final InterfaceName interfaceName) { From 923751c297c4f0fb5a390ac6b45808f592611bfd Mon Sep 17 00:00:00 2001 From: Florian Bossert Date: Mon, 29 Jul 2024 09:11:25 +0200 Subject: [PATCH 3/3] Remove TeaStoreRules They will be added as project-specific rules in the benchmark repository --- .../plugin.xml | 8 -- .../extraction/rules/TeaStoreRules.xtend | 128 ------------------ 2 files changed, 136 deletions(-) delete mode 100644 bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend diff --git a/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml b/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml index a77897eb..e2b31a2d 100644 --- a/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml +++ b/bundles/org.palladiosimulator.retriever.extraction.rules/plugin.xml @@ -81,13 +81,5 @@ class="org.palladiosimulator.retriever.extraction.rules.JaxRSDeploymentRules"> - - - - diff --git a/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend b/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend deleted file mode 100644 index c1efcc25..00000000 --- a/bundles/org.palladiosimulator.retriever.extraction.rules/src/org/palladiosimulator/retriever/extraction/rules/TeaStoreRules.xtend +++ /dev/null @@ -1,128 +0,0 @@ -package org.palladiosimulator.retriever.extraction.rules - -import java.nio.file.Path; -import java.util.HashSet -import org.eclipse.jdt.core.dom.CompilationUnit -import java.util.Set -import org.palladiosimulator.retriever.services.blackboard.RetrieverBlackboard -import org.palladiosimulator.retriever.services.Rule -import org.palladiosimulator.retriever.extraction.engine.PCMDetector -import org.palladiosimulator.retriever.extraction.commonalities.CompUnitOrName -import java.util.Map -import static org.palladiosimulator.retriever.extraction.engine.RuleHelper.* -import org.eclipse.jdt.core.dom.ASTVisitor -import org.eclipse.jdt.core.dom.ExpressionStatement -import org.eclipse.jdt.core.dom.MethodInvocation -import org.palladiosimulator.retriever.extraction.commonalities.RESTOperationName -import org.palladiosimulator.retriever.extraction.commonalities.RESTName - -class TeaStoreRules implements Rule { - - static final String RULE_ID = "org.palladiosimulator.retriever.extraction.rules.teastore" - static final String JAVA_DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.java"; - static final String DOCKER_DISCOVERER_ID = "org.palladiosimulator.retriever.extraction.discoverers.docker"; - static final String JAX_RS_RULE_ID = "org.palladiosimulator.retriever.extraction.rules.jax_rs"; - static final String JAX_RS_DEPLOYMENT_RULE_ID = "org.palladiosimulator.retriever.extraction.rules.jax_rs.deployment"; - static final String DOCKER_FILE_NAME = "Dockerfile"; - - override processRules(RetrieverBlackboard blackboard, Path path) { - if (path === null) { - return - } - - val compilationUnits = blackboard.getDiscoveredFiles(JAVA_DISCOVERER_ID, typeof(CompilationUnit)); - val pcmDetector = blackboard.PCMDetector as PCMDetector; - - if (path.fileName.toString().equals(DOCKER_FILE_NAME)) { - val parentName = path.parent.fileName.toString() - - // Add all file system children as associated compilation units - var children = new HashSet(); - var parentPath = path.parent; - for (entry : compilationUnits.entrySet) { - if (entry.key.startsWith(parentPath)) { - children.add(entry.value); - } - } - for (unit : children) { - pcmDetector.detectSeparatingIdentifier(new CompUnitOrName(unit), parentName) - pcmDetector.detectPartOfWeakComposite(new CompUnitOrName(unit), parentName) - } - - val hostnameMap = blackboard.getPartition(JAX_RS_DEPLOYMENT_RULE_ID) as Map - var hasHostnamePath = false - for (hostnamePath : hostnameMap.keySet) { - if (hostnamePath !== null && path.startsWith(hostnamePath)) { - hasHostnamePath = true - } - } - if (!hasHostnamePath) { - hostnameMap.put(path.parent, parentName) - } - } - - if (compilationUnits.containsKey(path)) { - val unit = compilationUnits.get(path) - val identifier = new CompUnitOrName(unit) - if (identifier.name().endsWith("Startup") && !identifier.name.endsWith("LogReaderStartup")) { - // Make Startup components part of a composite so that they become part of the weak Dockerfile composite - pcmDetector.detectPartOfComposite(identifier, identifier.name() + "_tempComposite") - val contextInitializedMethod = getMethods(unit).stream().filter[m|m.name.fullyQualifiedName.endsWith("contextInitialized")].findFirst() - if (contextInitializedMethod.present) { - contextInitializedMethod.get.accept(new TeaStoreASTVisitor(identifier, pcmDetector)); - } - } else if (identifier.name().endsWith("ServiceLoadBalancer")) { - pcmDetector.detectComponent(identifier) - } else if (identifier.name().endsWith("RegistryClient")) { - pcmDetector.detectComponent(identifier) - pcmDetector.detectRequiredInterface(identifier, new RESTName("tools.descartes.teastore.registry", "/services")) - } - } - } - - static class TeaStoreASTVisitor extends ASTVisitor { - CompUnitOrName identifier; - PCMDetector pcmDetector; - - new(CompUnitOrName identifier, PCMDetector pcmDetector) { - this.identifier = identifier; - this.pcmDetector = pcmDetector - } - - override visit(ExpressionStatement statement) { - if (!(statement.expression instanceof MethodInvocation)) { - return true - } - - val invocation = statement.expression as MethodInvocation - // TODO: avoid self-references - pcmDetector.detectCompositeRequiredInterfaceWeakly(identifier, invocation) - - return true - } - } - - override isBuildRule() { - return false - } - - override getConfigurationKeys() { - return Set.of - } - - override getID() { - return RULE_ID - } - - override getName() { - return "TeaStore Rules" - } - - override getRequiredServices() { - return Set.of(JAVA_DISCOVERER_ID, DOCKER_DISCOVERER_ID, JAX_RS_DEPLOYMENT_RULE_ID) - } - - override getDependentServices() { - Set.of(JAX_RS_RULE_ID) - } -}