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/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/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 1002d9b3..50b71bce 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
@@ -2,6 +2,8 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -14,6 +16,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 +47,9 @@ 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 final Set blacklist = new HashSet<>();
private static String getFullUnitName(final CompUnitOrName unit) {
// TODO this is potentially problematic, maybe restructure
@@ -73,14 +79,13 @@ private static String getFullUnitName(final CompUnitOrName unit) {
public void detectComponent(final CompUnitOrName unit) {
if (!unit.isUnit()) {
- this.components.put(unit, new ComponentBuilder(unit));
+ tryAddComponent(unit);
return;
}
for (final Object type : unit.compilationUnit()
.get()
.types()) {
- if (type instanceof TypeDeclaration) {
- this.components.put(unit, new ComponentBuilder(unit));
+ if (type instanceof TypeDeclaration && tryAddComponent(unit)) {
final ITypeBinding binding = ((TypeDeclaration) type).resolveBinding();
this.detectProvidedInterfaceWeakly(unit, binding);
}
@@ -93,8 +98,8 @@ public void detectRequiredInterface(final CompUnitOrName unit, final InterfaceNa
private void detectRequiredInterface(final CompUnitOrName unit, final InterfaceName interfaceName,
final boolean compositeRequired) {
- if (this.components.get(unit) == null) {
- this.components.put(unit, new ComponentBuilder(unit));
+ if (!tryAddComponent(unit)) {
+ return;
}
final EntireInterface iface = new EntireInterface(interfaceName);
this.detectRequiredInterface(unit, compositeRequired, false, iface);
@@ -110,8 +115,8 @@ public void detectRequiredInterfaceWeakly(final CompUnitOrName unit, final Field
private void detectRequiredInterface(final CompUnitOrName unit, final FieldDeclaration field,
final boolean compositeRequired, final boolean detectWeakly) {
- if (this.components.get(unit) == null) {
- this.components.put(unit, new ComponentBuilder(unit));
+ if (!tryAddComponent(unit)) {
+ return;
}
@SuppressWarnings("unchecked")
final List ifaces = ((List) field.fragments()).stream()
@@ -123,9 +128,23 @@ 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 (!tryAddComponent(unit)) {
+ return;
+ }
+ 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));
+ if (!tryAddComponent(unit)) {
+ return;
}
final IVariableBinding parameterBinding = parameter.resolveBinding();
if (parameterBinding == null) {
@@ -224,8 +243,8 @@ public void detectProvidedOperation(final CompUnitOrName unit, final IMethodBind
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));
+ if (!tryAddComponent(unit)) {
+ return;
}
final OperationInterface provision = new Operation(method, name);
this.detectProvidedInterface(unit, provision, compositeProvided, detectWeakly);
@@ -259,15 +278,63 @@ private void detectProvidedInterface(final CompUnitOrName unit, final OperationI
}
}
- public void detectPartOfComposite(final CompUnitOrName unit, final String compositeName) {
+ 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);
+ }
+ }
+
+ public void detectPartOfComposite(final CompUnitOrName unit, final String compositeName) {
+ if (!tryAddComponent(unit)) {
+ return;
}
if (!this.composites.containsKey(compositeName)) {
this.composites.put(compositeName, new CompositeBuilder(compositeName));
}
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) {
@@ -302,4 +369,40 @@ 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;
+ }
+
+ public void addToBlacklist(String string) {
+ this.blacklist.add(string);
+
+ // Clean up already added but now blacklisted components
+ List toDelete = new LinkedList<>();
+ for (CompUnitOrName unit : this.components.keySet()) {
+ if (unit.name()
+ .equals(string)) {
+ toDelete.add(unit);
+ }
+ }
+ for (CompUnitOrName unit : toDelete) {
+ this.components.remove(unit);
+ }
+ }
+
+ private boolean tryAddComponent(CompUnitOrName unit) {
+ if (this.components.get(unit) != null) {
+ return true;
+ }
+ if (this.blacklist.contains(unit.name())) {
+ return false;
+ }
+ this.components.put(unit, new ComponentBuilder(unit));
+ return true;
+ }
}