From 2b5ddd791af5d7993ccff4cef7d82175dac27114 Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Mon, 22 Sep 2025 09:42:18 +0200 Subject: [PATCH 1/5] docs(core): add documenation for resource provider and CDA state --- .../MemoryGDPRResourceProvider.java | 2 +- .../analysis/core/ContextAttributeState.java | 30 ++++++++++++++++ .../core/resource/GDPRResourceProvider.java | 34 +++++++++++++++++-- .../resource/GDPRURIResourceProvider.java | 26 ++++++-------- .../dfd/DFDGDPRFlowGraphCollection.java | 2 +- 5 files changed, 74 insertions(+), 20 deletions(-) diff --git a/bundles/mdpa.gdpr.analysis.validation/src/mdpa/gdpr/analysis/validation/MemoryGDPRResourceProvider.java b/bundles/mdpa.gdpr.analysis.validation/src/mdpa/gdpr/analysis/validation/MemoryGDPRResourceProvider.java index e35d447..7087051 100644 --- a/bundles/mdpa.gdpr.analysis.validation/src/mdpa/gdpr/analysis/validation/MemoryGDPRResourceProvider.java +++ b/bundles/mdpa.gdpr.analysis.validation/src/mdpa/gdpr/analysis/validation/MemoryGDPRResourceProvider.java @@ -14,7 +14,7 @@ public MemoryGDPRResourceProvider(GDPRModelBuilder modelBuilder) { } @Override - public LegalAssessmentFacts getModel() { + public LegalAssessmentFacts getGDPRModel() { return modelBuilder.getGdprModel(); } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java index 2c91eac..5ddecc6 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java @@ -5,27 +5,51 @@ import java.util.List; import java.util.stream.Collectors; +/** + * This class models a state for a {@link mdpa.gdpr.analysis.dfd.DFDGDPRTransposeFlowGraph} that has selected the stored {@link ContextDependentAttributeScenario} + */ public class ContextAttributeState { private final List selectedScenarios; + /** + * Creates a new {@link ContextAttributeState} using the given list of selected {@link ContextDependentAttributeScenario} + * @param selectedScenarios List of selected {@link ContextDependentAttributeScenario} + */ public ContextAttributeState(List selectedScenarios) { this.selectedScenarios = new ArrayList<>(selectedScenarios); } + /** + * Creates a new {@link ContextAttributeState} using the given list of selected {@link ContextDependentAttributeScenario} + * @param selectedScenarios List of selected {@link ContextDependentAttributeScenario} + */ public ContextAttributeState(ContextDependentAttributeScenario... selectedScenarios) { this(List.of(selectedScenarios)); } + /** + * Returns the list of {@link ContextDependentAttributeSource} that the selected {@link ContextDependentAttributeScenario} use + * @return Returns the {@link ContextDependentAttributeSource} of the selected scenarios + */ public List getContextAttributeSources() { return this.selectedScenarios.stream() .map(ContextDependentAttributeScenario::getContextDependentAttributeSource) .toList(); } + /** + * Returns the selected {@link ContextDependentAttributeScenario} that are selected by the {@link ContextAttributeState} + * @return Returns selected {@link ContextDependentAttributeScenario} + */ public List getSelectedScenarios() { return Collections.unmodifiableList(this.selectedScenarios); } + /** + * Create all possible {@link ContextAttributeState} that are possible to create from the given list of {@link ContextDependentAttributeSource} + * @param contextDependentAttributeSources Given list of {@link ContextDependentAttributeSource} that are used in finding all {@link ContextAttributeState} + * @return Returns a list of all possible {@link ContextAttributeState} + */ public static List createAllContextAttributeStates( List contextDependentAttributeSources) { List> scenarios = new ArrayList<>(); @@ -38,6 +62,12 @@ public static List createAllContextAttributeStates( .toList(); } + /** + * Calculates the cartesian product between the given lists + * @param lists List of lists that should be used when calculating the cartesian product + * @return Returns the cartesian product of the provided lists + * @param Type of the list elements + */ private static List> cartesianProduct(List> lists) { List> result = new ArrayList<>(); if (lists == null || lists.isEmpty()) { diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java index 7da908e..ab1ebd8 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java @@ -1,24 +1,52 @@ package mdpa.gdpr.analysis.core.resource; import mdpa.gdpr.analysis.core.TransformationManager; +import mdpa.gdpr.metamodel.GDPR.GDPRPackage; import mdpa.gdpr.metamodel.GDPR.LegalAssessmentFacts; import mdpa.gdpr.metamodel.contextproperties.ContextDependentProperties; +import mdpa.gdpr.metamodel.contextproperties.ContextpropertiesPackage; import org.dataflowanalysis.analysis.resource.ResourceProvider; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; +/** + * A {@link ResourceProvider} providing the necessary resources to run a {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} + */ public abstract class GDPRResourceProvider extends ResourceProvider { @Override public void setupResources() { - + this.resources.getPackageRegistry() + .put(GDPRPackage.eNS_URI, GDPRPackage.eINSTANCE); + this.resources.getResourceFactoryRegistry() + .getExtensionToFactoryMap() + .put(GDPRPackage.eNAME, new XMIResourceFactoryImpl()); + this.resources.getPackageRegistry() + .put(ContextpropertiesPackage.eNS_URI, ContextpropertiesPackage.eINSTANCE); + this.resources.getResourceFactoryRegistry() + .getExtensionToFactoryMap() + .put(ContextpropertiesPackage.eNAME, new XMIResourceFactoryImpl()); } - public abstract LegalAssessmentFacts getModel(); + /** + * Returns the loaded GDPR model + * + * @return Returns the GDPR model that is loaded by the resource provider + */ + public abstract LegalAssessmentFacts getGDPRModel(); + /** + * Returns the {@link ContextDependentProperties} metamodel that is required to run a {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} + * @return Returns the loaded Context Property model + */ public abstract ContextDependentProperties getContextDependentProperties(); + /** + * Returns the transformation manager that should be used for the transformation from gdpr to dfd + * @return Returns the {@link TransformationManager} of the running analysis + */ public abstract TransformationManager getTransformationManager(); @Override public boolean sufficientResourcesLoaded() { - return this.getModel() != null; + return this.getGDPRModel() != null; } } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java index 74b493c..c701051 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java @@ -12,6 +12,9 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; +/** + * Implementation of an {@link GDPRResourceProvider} using modelling project URIs to load the required models + */ public class GDPRURIResourceProvider extends GDPRResourceProvider { private final URI modelURI; private final URI propertyURI; @@ -19,26 +22,19 @@ public class GDPRURIResourceProvider extends GDPRResourceProvider { private ContextDependentProperties contextDependentProperties; private final TransformationManager transformationManager; + /** + * Creates a new {@link GDPRURIResourceProvider} using the provided URIs to the models + *

+ * Usually, the resource provider will be created automatically when using {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysisBuilder} + * @param modelURI URI path to the GDPR model + * @param propertyURI URI path to the context property model + */ public GDPRURIResourceProvider(URI modelURI, URI propertyURI) { this.modelURI = modelURI; this.propertyURI = propertyURI; this.transformationManager = new TransformationManager(); } - @Override - public void setupResources() { - this.resources.getPackageRegistry() - .put(GDPRPackage.eNS_URI, GDPRPackage.eINSTANCE); - this.resources.getResourceFactoryRegistry() - .getExtensionToFactoryMap() - .put(GDPRPackage.eNAME, new XMIResourceFactoryImpl()); - this.resources.getPackageRegistry() - .put(ContextpropertiesPackage.eNS_URI, ContextpropertiesPackage.eINSTANCE); - this.resources.getResourceFactoryRegistry() - .getExtensionToFactoryMap() - .put(ContextpropertiesPackage.eNAME, new XMIResourceFactoryImpl()); - } - @Override public void loadRequiredResources() { this.model = (LegalAssessmentFacts) this.loadModelContent(modelURI); @@ -52,7 +48,7 @@ public void loadRequiredResources() { } @Override - public LegalAssessmentFacts getModel() { + public LegalAssessmentFacts getGDPRModel() { return this.model; } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java index add84be..8023fcc 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java @@ -43,7 +43,7 @@ public List findTransposeFlowGraphs() { throw new IllegalArgumentException(); } DataFlowDiagramAndDataDictionary dfd = gdprResourceProvider.getTransformationManager() - .transform(gdprResourceProvider.getModel(), gdprResourceProvider.getContextDependentProperties()); + .transform(gdprResourceProvider.getGDPRModel(), gdprResourceProvider.getContextDependentProperties()); DFDTransposeFlowGraphFinder finder = new DFDTransposeFlowGraphFinder(dfd.dataDictionary(), dfd.dataFlowDiagram()); List completeFlowGraphs = finder.findTransposeFlowGraphs() .stream() From b1e4fd1363f92d32452c0eae2755b6190878f11a Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Mon, 22 Sep 2025 11:20:07 +0200 Subject: [PATCH 2/5] refactor(core): refactor and document most analysis classes --- .../analysis/GDPRLegalAssessmentAnalysis.java | 16 ++ .../GDPRLegalAssessmentAnalysisBuilder.java | 6 + .../analysis/core/ContextAttributeState.java | 36 ++-- .../ContextDependentAttributeScenario.java | 61 ++++-- .../core/ContextDependentAttributeSource.java | 55 +++++- .../analysis/core/TransformationManager.java | 84 ++++---- .../resource/GDPRURIResourceProvider.java | 3 - .../dfd/DFDGDPRFlowGraphCollection.java | 182 +++++++++--------- .../dfd/DFDGDPRTransposeFlowGraph.java | 4 +- .../dfd/DataFlowDiagramAndDataDictionary.java | 27 +-- .../validation/TrainModelEvaluation.java | 2 +- .../validation/TravelPlannerEvaluation.java | 4 +- 12 files changed, 278 insertions(+), 202 deletions(-) diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysis.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysis.java index 88b493b..8083662 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysis.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysis.java @@ -12,6 +12,14 @@ import tools.mdsd.library.standalone.initialization.StandaloneInitializationException; import tools.mdsd.library.standalone.initialization.StandaloneInitializerBuilder; +/** + * Extension of the {@link DataFlowConfidentialityAnalysis} for usage with the GDPR metamodel that is able to resolve + * uncertain context dependent attributes. + *

+ * Inputs to the analysis are a metamodel instance of the GDPR model and the context properties model + *

+ * Note: Do not create an instance of this class manually, use the {@link GDPRLegalAssessmentAnalysisBuilder} instead + */ public class GDPRLegalAssessmentAnalysis extends DataFlowConfidentialityAnalysis { public static final String PLUGIN_PATH = "mdpa.gdpr.analysis"; @@ -21,6 +29,14 @@ public class GDPRLegalAssessmentAnalysis extends DataFlowConfidentialityAnalysis private final Optional> modelProjectActivator; private final String modelProjectName; + /** + * Create a new {@link GDPRLegalAssessmentAnalysis} with the given resource provider and optionally a modelling project with a plugin activator + *

+ * Note: Do not create an instance of this class manually, use the {@link GDPRLegalAssessmentAnalysisBuilder} instead + * @param resourceProvider {@link GDPRResourceProvider} providing a metamodel instance of the GDPR and Context Property model + * @param modelProjectActivator Optional model project activator + * @param modelProjectName Optional model project name + */ public GDPRLegalAssessmentAnalysis(GDPRResourceProvider resourceProvider, Optional> modelProjectActivator, String modelProjectName) { this.resourceProvider = resourceProvider; diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java index a1020ff..61849d5 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java @@ -8,6 +8,12 @@ import org.dataflowanalysis.analysis.utils.ResourceUtils; import org.eclipse.core.runtime.Plugin; +/** + * Extension of the {@link DataFlowAnalysisBuilder} responsible for creating a valid {@link GDPRLegalAssessmentAnalysis} + * from the following: + * - A valid path to a .gdpr metamodel instance + * - A valid path to a .contextproperties metamodel instance + */ public class GDPRLegalAssessmentAnalysisBuilder extends DataFlowAnalysisBuilder { private final Logger logger = Logger.getLogger(GDPRLegalAssessmentAnalysisBuilder.class); diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java index 5ddecc6..3341922 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextAttributeState.java @@ -1,5 +1,7 @@ package mdpa.gdpr.analysis.core; +import org.eclipse.jdt.annotation.NonNull; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -8,45 +10,29 @@ /** * This class models a state for a {@link mdpa.gdpr.analysis.dfd.DFDGDPRTransposeFlowGraph} that has selected the stored {@link ContextDependentAttributeScenario} */ -public class ContextAttributeState { - private final List selectedScenarios; - +public record ContextAttributeState(List selectedScenarios) { /** * Creates a new {@link ContextAttributeState} using the given list of selected {@link ContextDependentAttributeScenario} + * * @param selectedScenarios List of selected {@link ContextDependentAttributeScenario} */ public ContextAttributeState(List selectedScenarios) { this.selectedScenarios = new ArrayList<>(selectedScenarios); } - /** - * Creates a new {@link ContextAttributeState} using the given list of selected {@link ContextDependentAttributeScenario} - * @param selectedScenarios List of selected {@link ContextDependentAttributeScenario} - */ - public ContextAttributeState(ContextDependentAttributeScenario... selectedScenarios) { - this(List.of(selectedScenarios)); - } - - /** - * Returns the list of {@link ContextDependentAttributeSource} that the selected {@link ContextDependentAttributeScenario} use - * @return Returns the {@link ContextDependentAttributeSource} of the selected scenarios - */ - public List getContextAttributeSources() { - return this.selectedScenarios.stream() - .map(ContextDependentAttributeScenario::getContextDependentAttributeSource) - .toList(); - } - /** * Returns the selected {@link ContextDependentAttributeScenario} that are selected by the {@link ContextAttributeState} + * * @return Returns selected {@link ContextDependentAttributeScenario} */ - public List getSelectedScenarios() { + @Override + public List selectedScenarios() { return Collections.unmodifiableList(this.selectedScenarios); } /** * Create all possible {@link ContextAttributeState} that are possible to create from the given list of {@link ContextDependentAttributeSource} + * * @param contextDependentAttributeSources Given list of {@link ContextDependentAttributeSource} that are used in finding all {@link ContextAttributeState} * @return Returns a list of all possible {@link ContextAttributeState} */ @@ -64,9 +50,10 @@ public static List createAllContextAttributeStates( /** * Calculates the cartesian product between the given lists + * * @param lists List of lists that should be used when calculating the cartesian product + * @param Type of the list elements * @return Returns the cartesian product of the provided lists - * @param Type of the list elements */ private static List> cartesianProduct(List> lists) { List> result = new ArrayList<>(); @@ -91,9 +78,10 @@ private static List> cartesianProduct(List> lists) { } @Override + @NonNull public String toString() { String scenarios = this.selectedScenarios.stream() - .map(it -> it.getName()) + .map(ContextDependentAttributeScenario::getName) .collect(Collectors.joining(",")); return "[" + scenarios + "]"; } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeScenario.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeScenario.java index f9d216f..3053b23 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeScenario.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeScenario.java @@ -9,11 +9,16 @@ import mdpa.gdpr.metamodel.contextproperties.PropertyValue; import org.apache.log4j.Logger; +/** + * Models a Context Dependent Attribute Scenario that applies the given list of property values. + *

+ * As a Context Dependent Attribute Scenario can occur in two scenarios we differentiate: + * + */ public class ContextDependentAttributeScenario { private final Logger logger = Logger.getLogger(ContextDependentAttributeScenario.class); private final String name; - private final TransformationManager transformationManager; private final List propertyValues; private final List context; @@ -21,9 +26,14 @@ public class ContextDependentAttributeScenario { private final ContextDependentAttributeSource contextDependentAttributeSource; private final boolean resolvedUncertainty; + /** + * Creates a new context dependent attribute scenario that matches a specific context. + * Therefore, it does not resolve an uncertain CDA + * @param contextAnnotation {@link ContextAnnotation} the Scenario requires + * @param contextDependentAttributeSource Corresponding {@link ContextDependentAttributeSource} + */ public ContextDependentAttributeScenario(ContextAnnotation contextAnnotation, ContextDependentAttributeSource contextDependentAttributeSource) { this.name = contextAnnotation.getEntityName(); - this.transformationManager = new TransformationManager(); this.propertyValues = contextAnnotation.getPropertyvalue(); this.context = contextAnnotation.getContextdefinition(); this.sources = List.of(); @@ -31,10 +41,17 @@ public ContextDependentAttributeScenario(ContextAnnotation contextAnnotation, Co this.resolvedUncertainty = false; } + /** + * Creates a new {@link ContextDependentAttributeScenario} that is resolving an uncertainty. + * Therefore, it requires a property value that is applied, the corresponding {@link ContextDependentAttributeSource} + * and a list of other {@link ContextDependentAttributeSource} that contradict the uncertain CDA + * @param propertyValue Property value that is applied, when this scenario is applied + * @param contextDependentAttributeSource Corresponding {@link ContextDependentAttributeSource} + * @param sources Other {@link ContextDependentAttributeSource} that must not be true + */ public ContextDependentAttributeScenario(PropertyValue propertyValue, ContextDependentAttributeSource contextDependentAttributeSource, List sources) { this.name = propertyValue.getEntityName() + "@" + contextDependentAttributeSource.getName(); - this.transformationManager = new TransformationManager(); this.propertyValues = List.of(propertyValue); this.context = List.of(); this.sources = sources; @@ -42,21 +59,27 @@ public ContextDependentAttributeScenario(PropertyValue propertyValue, ContextDep this.resolvedUncertainty = true; } + /** + * Returns whether the {@link ContextDependentAttributeScenario} is applicable to the given vertex + * @param vertex {@link DFDGDPRVertex} that is checked + * @return Returns true, if the scenario should be applied to the vertex. + * Otherwise, the method returns false + */ public boolean applicable(DFDGDPRVertex vertex) { - logger.info("Determining whether " + this.name + " can be applied to " + vertex); + logger.trace("Determining whether " + this.name + " can be applied to " + vertex); if (this.resolvedUncertainty) { if (!this.contextDependentAttributeSource.applicable(vertex)) { return false; } - logger.info("Context Depdendent Attribute Scenario is resolved with uncertainties!"); + logger.trace("Context Dependent Attribute Scenario is resolved with uncertainties!"); return this.sources.stream() .noneMatch(it -> { - logger.info("Should not match: " + it.getContextDependentAttributeScenarios() + logger.trace("Should not match: " + it.getContextDependentAttributeScenarios() .get(0) .getName()); var scenario = it.getContextDependentAttributeScenarios() .get(0); - logger.info("Result: " + scenario.applicable(vertex)); + logger.trace("Result: " + scenario.applicable(vertex)); return scenario.applicable(vertex); }); } @@ -64,6 +87,12 @@ public boolean applicable(DFDGDPRVertex vertex) { .anyMatch(it -> UncertaintyUtils.matchesContextDefinition(vertex, it)); } + /** + * Determines whether the {@link ContextDependentAttributeScenario} is applicable to any of the nodes in the given transpose flow graph + * @param transposeFlowGraph {@link DFDGDPRTransposeFlowGraph} that is checked + * @return Returns true, if the {@link ContextDependentAttributeScenario} can be applied to any of the vertices in the TFG. + * Otherwise, the method returns false + */ public boolean applicable(DFDGDPRTransposeFlowGraph transposeFlowGraph) { if (this.resolvedUncertainty) { return this.sources.stream() @@ -77,21 +106,29 @@ public boolean applicable(DFDGDPRTransposeFlowGraph transposeFlowGraph) { .stream() .filter(DFDGDPRVertex.class::isInstance) .map(DFDGDPRVertex.class::cast) - .anyMatch(it -> this.applicable(it)); + .anyMatch(this::applicable); } + /** + * Returns the property values that are applied, when this scenario is fulfilled + * @return Returns a list of {@link PropertyValue} that are applied in the case the scenario is true + */ public List getPropertyValues() { return this.propertyValues; } - public boolean resolvedByUncertainty() { - return this.resolvedUncertainty; - } - + /** + * Retrieves the {@link ContextDependentAttributeSource} that this scenario is a part of + * @return Returns the parent {@link ContextDependentAttributeSource} + */ public ContextDependentAttributeSource getContextDependentAttributeSource() { return contextDependentAttributeSource; } + /** + * Returns the name of the {@link ContextDependentAttributeScenario} + * @return The name of the {@link ContextDependentAttributeScenario} + */ public String getName() { return name; } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java index aa818c1..bd6d7e7 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java @@ -11,6 +11,10 @@ import mdpa.gdpr.metamodel.contextproperties.PropertyAnnotation; import mdpa.gdpr.metamodel.contextproperties.PropertyValue; +/** + * This class models an application of a context dependent attribute on an element in the GDPR model. + * The different values it can take are saved in one or multiple child {@link ContextDependentAttributeScenario}. + */ public class ContextDependentAttributeSource { private final String name; private final AbstractGDPRElement annotatedElement; @@ -21,6 +25,12 @@ public class ContextDependentAttributeSource { private final List sources; private final boolean resolvedUncertainty; + /** + * Creates a new {@link ContextDependentAttributeSource} with the given property annotation containing the information about the annotated element and value + * and the context annotation describing the context of the {@link ContextDependentAttributeSource} + * @param propertyAnnotation {@link PropertyAnnotation} describing where the CDA is applied + * @param contextAnnotation {@link ContextAnnotation} describing which scenarios the source has + */ public ContextDependentAttributeSource(PropertyAnnotation propertyAnnotation, ContextAnnotation contextAnnotation) { this.name = contextAnnotation.getEntityName() + "@" + propertyAnnotation.getEntityName(); this.annotatedElement = propertyAnnotation.getAnnotatedElement(); @@ -31,6 +41,15 @@ public ContextDependentAttributeSource(PropertyAnnotation propertyAnnotation, Co this.resolvedUncertainty = false; } + /** + * Creates a new {@link ContextDependentAttributeSource} that needs to be resolved with uncertain CDAs. + * Resolves an uncertainty regarding the value of an {@link ContextDependentAttributeSource} by creating a scenario for each + * passed {@link PropertyValue}. + * Additionally, the given list of other {@link ContextDependentAttributeSource} denotes where this source cannot apply + * @param propertyAnnotation {@link PropertyAnnotation} containing information about the annotated element and value + * @param values Different {@link PropertyValue} that are resolved by the uncertainty + * @param sources List of {@link ContextDependentAttributeSource} that cannot be applied at the same time + */ public ContextDependentAttributeSource(PropertyAnnotation propertyAnnotation, List values, List sources) { this.name = "Unknown@" + propertyAnnotation.getEntityName(); @@ -44,18 +63,34 @@ public ContextDependentAttributeSource(PropertyAnnotation propertyAnnotation, Li this.resolvedUncertainty = true; } + /** + * Determines whether this {@link ContextDependentAttributeSource} is applicable to the given list of vertices + * @param vertices Given list of vertices + * @return Returns true, if this {@link ContextDependentAttributeSource} is applicable at least one of the vertices + * Otherwise, the method returns false. + */ public boolean applicable(Collection vertices) { if (!vertices.stream() - .map(it -> it.getRelatedElements()) + .map(DFDGDPRVertex::getRelatedElements) .flatMap(List::stream) .toList() .contains(this.annotatedElement)) { return false; } return vertices.stream() - .anyMatch(it -> this.applicable(it)); + .anyMatch(this::applicable); } + /** + * Determines whether the {@link ContextDependentAttributeSource} is applicable at the given vertex. + *

+ * This is the case, it the vertex has the annotated element in its context. + * If this {@link ContextDependentAttributeSource} is resolving an uncertainty, the other saved sources must not match. + * If this source is not resolving an uncertainty, it must match at least one context definition + * @param vertex Given {@link DFDGDPRVertex} that is checked + * @return Returns true, if the source is applicable to the vertex. + * Otherwise, the method returns false + */ public boolean applicable(DFDGDPRVertex vertex) { if (!vertex.getRelatedElements() .contains(this.annotatedElement)) { @@ -69,18 +104,34 @@ public boolean applicable(DFDGDPRVertex vertex) { .anyMatch(it -> UncertaintyUtils.matchesContextDefinition(vertex, it)); } + /** + * Returns the property type that will be applied if the source is applicable + * @return Returns the applied {@link Property} + */ public Property getPropertyType() { return propertyType; } + /** + * Returns the different possible {@link ContextDependentAttributeScenario} of this source + * @return List of possible {@link ContextDependentAttributeScenario} + */ public List getContextDependentAttributeScenarios() { return contextDependentAttributeScenarios; } + /** + * Returns the {@link AbstractGDPRElement} the source is annotated to + * @return Annotated {@link AbstractGDPRElement} + */ public AbstractGDPRElement getAnnotatedElement() { return annotatedElement; } + /** + * Returns the name of the {@link ContextDependentAttributeSource} + * @return Returns the name of the source + */ public String getName() { return name; } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java index a958666..217c442 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java @@ -7,54 +7,59 @@ import java.util.Optional; import mdpa.gdpr.analysis.dfd.DataFlowDiagramAndDataDictionary; import mdpa.gdpr.dfdconverter.GDPR2DFD; -import mdpa.gdpr.metamodel.GDPR.AbstractGDPRElement; -import mdpa.gdpr.metamodel.GDPR.Collecting; import mdpa.gdpr.metamodel.GDPR.LegalAssessmentFacts; import mdpa.gdpr.metamodel.GDPR.Processing; -import mdpa.gdpr.metamodel.GDPR.Storing; import mdpa.gdpr.metamodel.contextproperties.ContextDependentProperties; import mdpa.gdpr.metamodel.contextproperties.Property; import mdpa.gdpr.metamodel.contextproperties.PropertyAnnotation; import mdpa.gdpr.metamodel.contextproperties.PropertyValue; import org.apache.log4j.Logger; import org.dataflowanalysis.dfd.datadictionary.DataDictionary; -import org.dataflowanalysis.dfd.datadictionary.ForwardingAssignment; import org.dataflowanalysis.dfd.datadictionary.Label; import org.dataflowanalysis.dfd.datadictionary.LabelType; import org.dataflowanalysis.dfd.datadictionary.datadictionaryFactory; import org.dataflowanalysis.dfd.dataflowdiagram.DataFlowDiagram; import org.dataflowanalysis.dfd.dataflowdiagram.Node; +/** + * Manages the transformation from GDPR to DFD that is required to find {@link org.dataflowanalysis.analysis.core.AbstractTransposeFlowGraph} for the analysis. + */ public class TransformationManager { private final Logger logger = Logger.getLogger(TransformationManager.class); - private final Map> relatedElementMapping; - private final Map gdprToDFDMapping; private final Map dfdToGDPRMapping; private final List contextDependentAttributes; + /** + * Creates a new empty {@link TransformationManager} + */ public TransformationManager() { - this.relatedElementMapping = new HashMap<>(); - this.gdprToDFDMapping = new HashMap<>(); this.dfdToGDPRMapping = new HashMap<>(); this.contextDependentAttributes = new ArrayList<>(); } /** * Converts model to DFD and saves tracemodel - * @param gdprModel - * @return + * @param gdprModel Input GDPR Model + * @param contextDependentProperties Input context property model + * @return Returns the data flow diagram and data dictionary of the converted model */ public DataFlowDiagramAndDataDictionary transform(LegalAssessmentFacts gdprModel, ContextDependentProperties contextDependentProperties) { GDPR2DFD converter = new GDPR2DFD(gdprModel); converter.transform(); - processTransformation(converter.getDataFlowDiagram(), converter.getDataDictionary(), gdprModel); + processTransformation(converter.getDataFlowDiagram(), gdprModel); processContextDependentAttributes(contextDependentProperties, converter.getDataDictionary()); return new DataFlowDiagramAndDataDictionary(converter.getDataFlowDiagram(), converter.getDataDictionary()); } - private void processTransformation(DataFlowDiagram dfd, DataDictionary dd, LegalAssessmentFacts gdprModel) { - List nodes = dfd.getNodes(); + /** + * Runs some postprocessing on the resulting DFD model for keeping track of the trace between nodes and processing elements + * TODO: This can be replaced with the tracemodel + * @param dataFlowDiagram Data flow diagram of the Transformation + * @param gdprModel GDPR model of the transformation + */ + private void processTransformation(DataFlowDiagram dataFlowDiagram, LegalAssessmentFacts gdprModel) { + List nodes = dataFlowDiagram.getNodes(); for (Node node : nodes) { Processing gdprElement = gdprModel.getProcessing() .stream() @@ -66,12 +71,18 @@ private void processTransformation(DataFlowDiagram dfd, DataDictionary dd, Legal } } - private void processContextDependentAttributes(ContextDependentProperties propertyModel, DataDictionary dd) { + /** + * Creates the {@link ContextDependentAttributeSource}s and {@link ContextDependentAttributeScenario} for the context property model. + * Additionally, it creates the required labels in the data dictionary. + * @param propertyModel Context Property Model of the transformation + * @param dataDictionary Data Dictionary of the transformation + */ + private void processContextDependentAttributes(ContextDependentProperties propertyModel, DataDictionary dataDictionary) { for (Property property : propertyModel.getProperty()) { LabelType type = datadictionaryFactory.eINSTANCE.createLabelType(); type.setEntityName(property.getEntityName()); type.setId(property.getId()); - dd.getLabelTypes() + dataDictionary.getLabelTypes() .add(type); for (PropertyValue propertyValue : property.getPropertyvalue()) { Label label = datadictionaryFactory.eINSTANCE.createLabel(); @@ -89,7 +100,6 @@ private void processContextDependentAttributes(ContextDependentProperties proper } else { List sources = new ArrayList<>(); propertyAnnotation.getContextannotation() - .stream() .forEach(it -> { var source = new ContextDependentAttributeSource(propertyAnnotation, it); sources.add(source); @@ -102,42 +112,28 @@ private void processContextDependentAttributes(ContextDependentProperties proper logger.info("Parsed " + this.contextDependentAttributes.size() + " CDA!"); } - private void addAssignments(DataFlowDiagram dfd, DataDictionary dd) { - for (Node node : dfd.getNodes()) { - Processing gdprElement = this.getElement(node) - .orElseThrow(); - if (!(gdprElement instanceof Storing) && !(gdprElement instanceof Collecting)) { - ForwardingAssignment assignment = datadictionaryFactory.eINSTANCE.createForwardingAssignment(); - assignment.getInputPins() - .addAll(node.getBehavior() - .getInPin()); - if (!node.getBehavior() - .getOutPin() - .isEmpty()) { - assignment.setOutputPin(node.getBehavior() - .getOutPin() - .get(0)); - } - node.getBehavior() - .getAssignment() - .add(assignment); - } - } - } - + /** + * Adds a new mapping between the given GDPR {@link Processing} element an the DFD {@link Node} + * @param gdprElement Given {@link Processing} element + * @param dfdElement Given {@link Node} element + */ private void addMapping(Processing gdprElement, Node dfdElement) { - this.gdprToDFDMapping.put(gdprElement, dfdElement); this.dfdToGDPRMapping.put(dfdElement, gdprElement); } + /** + * Returns the GDPR {@link Processing} element that corresponds to the given node + * @param node Given DFD {@link Node} + * @return Returns the {@link Processing} element, if one exits + */ public Optional getElement(Node node) { return Optional.ofNullable(this.dfdToGDPRMapping.get(node)); } - public Optional getElement(Processing gdprElement) { - return Optional.ofNullable(this.gdprToDFDMapping.get(gdprElement)); - } - + /** + * Returns the list of {@link ContextDependentAttributeSource} that were parsed by the transformation + * @return Returns the list of parsed context dependent attributes from the metamodel instance + */ public List getContextDependentAttributes() { return this.contextDependentAttributes; } diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java index c701051..64af96a 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java @@ -3,14 +3,11 @@ import java.util.ArrayList; import java.util.List; import mdpa.gdpr.analysis.core.TransformationManager; -import mdpa.gdpr.metamodel.GDPR.GDPRPackage; import mdpa.gdpr.metamodel.GDPR.LegalAssessmentFacts; import mdpa.gdpr.metamodel.contextproperties.ContextDependentProperties; -import mdpa.gdpr.metamodel.contextproperties.ContextpropertiesPackage; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; /** * Implementation of an {@link GDPRResourceProvider} using modelling project URIs to load the required models diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java index 8023fcc..724302e 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java @@ -9,12 +9,9 @@ import mdpa.gdpr.analysis.core.ContextDependentAttributeSource; import mdpa.gdpr.analysis.core.resource.GDPRResourceProvider; import mdpa.gdpr.metamodel.GDPR.AbstractGDPRElement; -import mdpa.gdpr.metamodel.GDPR.Collecting; import mdpa.gdpr.metamodel.GDPR.PersonalData; +import mdpa.gdpr.metamodel.GDPR.Processing; import mdpa.gdpr.metamodel.GDPR.Role; -import mdpa.gdpr.metamodel.GDPR.Storing; -import mdpa.gdpr.metamodel.GDPR.Transferring; -import mdpa.gdpr.metamodel.GDPR.Usage; import org.apache.log4j.Logger; import org.dataflowanalysis.analysis.core.AbstractTransposeFlowGraph; import org.dataflowanalysis.analysis.core.FlowGraphCollection; @@ -25,13 +22,26 @@ import org.dataflowanalysis.dfd.datadictionary.DataDictionary; import org.dataflowanalysis.dfd.datadictionary.Pin; +/** + * Models a collection of {@link DFDGDPRTransposeFlowGraph}s for use with the {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} + */ public class DFDGDPRFlowGraphCollection extends FlowGraphCollection { private final Logger logger = Logger.getLogger(DFDGDPRFlowGraphCollection.class); + private DataDictionary dataDictionary; + /** + * Creates a new {@link DFDGDPRFlowGraphCollection} using the provided resource provider + * @param resourceProvider {@link ResourceProvider} that provides the necessary models + */ public DFDGDPRFlowGraphCollection(ResourceProvider resourceProvider) { super(resourceProvider); } + /** + * Creates a new {@link DFDGDPRFlowGraphCollection} with the given list of transpose flow graphs and a given resource provider + * @param transposeFlowGraphs List of {@link DFDGDPRTransposeFlowGraph}s that are stored in the flow graph collection + * @param resourceProvider {@link ResourceProvider} that has the relevant model elements loaded + */ public DFDGDPRFlowGraphCollection(List transposeFlowGraphs, ResourceProvider resourceProvider) { super(transposeFlowGraphs, resourceProvider); } @@ -44,30 +54,56 @@ public List findTransposeFlowGraphs() { } DataFlowDiagramAndDataDictionary dfd = gdprResourceProvider.getTransformationManager() .transform(gdprResourceProvider.getGDPRModel(), gdprResourceProvider.getContextDependentProperties()); + this.dataDictionary = dfd.dataDictionary(); DFDTransposeFlowGraphFinder finder = new DFDTransposeFlowGraphFinder(dfd.dataDictionary(), dfd.dataFlowDiagram()); List completeFlowGraphs = finder.findTransposeFlowGraphs() .stream() .map(it -> this.transformFlowGraph((DFDTransposeFlowGraph) it, dfd.dataDictionary())) .toList(); - List result = new ArrayList<>(completeFlowGraphs); - /* - * result.addAll(completeFlowGraphs.stream() .map(it -> this.getPartialTransposeFlowGraphs(it, dfd.dataDictionary())) - * .flatMap(List::stream) .toList()); - */ - return result; + return new ArrayList<>(completeFlowGraphs); + } + + /** + * Finds the partial responsibility flow graphs for the contained flow graphs and creates a new {@link DFDGDPRFlowGraphCollection} + * containing the previous {@link DFDGDPRTransposeFlowGraph} with the additional partial responsibility flow graphs + * @return Returns a new {@link DFDGDPRFlowGraphCollection} containing additional partial responsibility flow graphs + */ + public DFDGDPRFlowGraphCollection findResponsibilityFlowGraphs() { + List completeFlowGraphs = this.getTransposeFlowGraphs() + .stream() + .filter(DFDGDPRTransposeFlowGraph.class::isInstance) + .map(DFDGDPRTransposeFlowGraph.class::cast) + .toList(); + List flowGraphs = new ArrayList<>(completeFlowGraphs); + flowGraphs.addAll(completeFlowGraphs.stream() + .map(this::getPartialTransposeFlowGraphs) + .flatMap(List::stream) + .toList()); + return new DFDGDPRFlowGraphCollection(flowGraphs, this.resourceProvider); } - private DFDGDPRTransposeFlowGraph transformFlowGraph(DFDTransposeFlowGraph transposeFlowGraph, DataDictionary dd) { + /** + * Transforms the given DFD-based {@link DFDTransposeFlowGraph} to an {@link DFDGDPRTransposeFlowGraph} + * @param transposeFlowGraph Given {@link DFDTransposeFlowGraph} + * @param dataDictionary Data dictionary containing the labels for CDAs + * @return Returns the corresponding {@link DFDGDPRTransposeFlowGraph} + */ + private DFDGDPRTransposeFlowGraph transformFlowGraph(DFDTransposeFlowGraph transposeFlowGraph, DataDictionary dataDictionary) { Map mapping = new IdentityHashMap<>(); transposeFlowGraph.getVertices() .stream() .map(DFDVertex.class::cast) .forEach(vertex -> mapping.put(vertex, this.getDFDGDPRVertex(vertex, new IdentityHashMap<>()))); return new DFDGDPRTransposeFlowGraph(mapping.get((DFDVertex) transposeFlowGraph.getSink()), - this.determineContextDependentAttributes(transposeFlowGraph, mapping.values()), dd); + this.determineContextDependentAttributes(mapping.values()), dataDictionary); } - private List getPartialTransposeFlowGraphs(DFDGDPRTransposeFlowGraph transposeFlowGraph, DataDictionary dd) { + /** + * Determines the list of partial responsibility flow graphs for the given {@link DFDGDPRTransposeFlowGraph} + * @param transposeFlowGraph Given {@link DFDGDPRTransposeFlowGraph} + * @return Returns the list of responsibility transpose flow graphs for the input {@link DFDGDPRTransposeFlowGraph} + */ + private List getPartialTransposeFlowGraphs(DFDGDPRTransposeFlowGraph transposeFlowGraph) { List result = new ArrayList<>(); Map> roleMap = new HashMap<>(); transposeFlowGraph.getVertices() @@ -96,27 +132,37 @@ private List getPartialTransposeFlowGraphs(DFDGDPRTra .filter(it -> !previousElements.contains(it)) .toList(); for (DFDGDPRVertex sink : sinks) { - Map mapping = new HashMap<>(); - result.add(new DFDGDPRTransposeFlowGraph(this.getMappingForSink(sink, roleVertices, mapping), - new ArrayList<>(transposeFlowGraph.getContextDependentAttributeSources()), dd)); + result.add(new DFDGDPRTransposeFlowGraph(this.getMappingForSink(sink, roleVertices), + new ArrayList<>(transposeFlowGraph.getContextDependentAttributeSources()), this.dataDictionary)); } } return result; } - private DFDGDPRVertex getMappingForSink(DFDGDPRVertex sink, List roleVertices, Map mapping) { + /** + * Determines the {@link DFDGDPRVertex} that denotes the sink of the partial responsibility transpose flow graph + * @param sink {@link DFDGDPRVertex} that is the current sink + * @param roleVertices List of {@link DFDGDPRVertex} that denote the beginnings of each responsibility segment + * @return Returns the {@link DFDGDPRVertex} sink of the partial responsibility TFG + */ + private DFDGDPRVertex getMappingForSink(DFDGDPRVertex sink, List roleVertices) { Map pinVertexMap = new HashMap<>(); sink.getPinDFDVertexMap() .entrySet() .stream() + .filter(it -> it.getValue() instanceof DFDGDPRVertex) .filter(it -> roleVertices.contains(it.getValue())) - .forEach(it -> { - pinVertexMap.put(it.getKey(), this.getMappingForSink((DFDGDPRVertex) it.getValue(), roleVertices, mapping)); - }); + .forEach(it -> pinVertexMap.put(it.getKey(), this.getMappingForSink((DFDGDPRVertex) it.getValue(), roleVertices))); return new DFDGDPRVertex(sink.getReferencedElement(), pinVertexMap, new HashMap<>(sink.getPinFlowMap()), new ArrayList<>(sink.getRelatedElements())); } + /** + * Creates the {@link DFDGDPRVertex} for a corresponding {@link DFDVertex} and a given mapping + * @param vertex Given {@link DFDVertex} + * @param mapping Mapping between {@link DFDVertex} + * @return Returns the corresponding {@link DFDGDPRVertex} of the {@link DFDVertex} + */ private DFDGDPRVertex getDFDGDPRVertex(DFDVertex vertex, Map mapping) { if (!(this.resourceProvider instanceof GDPRResourceProvider gdprResourceProvider)) { this.logger.error("Resource provider is not a GDPR resource provider!"); @@ -136,96 +182,44 @@ private DFDGDPRVertex getDFDGDPRVertex(DFDVertex vertex, Map(vertex.getPinFlowMap()), relatedElements); } + /** + * Determines the relevant elements for the given {@link AbstractGDPRElement} + * @param gdprElement Given {@link AbstractGDPRElement} + * @return Related elements for the given {@link AbstractGDPRElement} + */ private List determineRelatedElements(AbstractGDPRElement gdprElement) { List result = new ArrayList<>(); result.add(gdprElement); - if (gdprElement instanceof Collecting collecting) { - result.addAll(collecting.getInputData()); - result.addAll(collecting.getInputData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .map(PersonalData::getDataReferences) - .flatMap(List::stream) - .toList()); - result.addAll(collecting.getOutputData()); - result.addAll(collecting.getOutputData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .map(PersonalData::getDataReferences) - .flatMap(List::stream) - .toList()); - result.addAll(collecting.getPurpose()); - result.addAll(collecting.getOnTheBasisOf()); - result.add(collecting.getResponsible()); - } else if (gdprElement instanceof Usage usage) { - result.addAll(usage.getInputData()); - result.addAll(usage.getInputData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .map(PersonalData::getDataReferences) - .flatMap(List::stream) - .toList()); - result.addAll(usage.getOutputData()); - result.addAll(usage.getOutputData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .map(PersonalData::getDataReferences) - .flatMap(List::stream) - .toList()); - result.addAll(usage.getPurpose()); - result.addAll(usage.getOnTheBasisOf()); - result.add(usage.getResponsible()); - } else if (gdprElement instanceof Transferring transferring) { - result.addAll(transferring.getInputData()); - result.addAll(transferring.getInputData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .map(PersonalData::getDataReferences) - .flatMap(List::stream) - .toList()); - result.addAll(transferring.getOutputData()); - result.addAll(transferring.getOutputData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .map(PersonalData::getDataReferences) - .flatMap(List::stream) - .toList()); - result.addAll(transferring.getPurpose()); - result.addAll(transferring.getOnTheBasisOf()); - result.add(transferring.getResponsible()); - - } else if (gdprElement instanceof Storing storing) { - result.addAll(storing.getInputData()); - result.addAll(storing.getInputData() + if (gdprElement instanceof Processing processing) { + result.addAll(processing.getInputData()); + result.addAll(processing.getInputData() .stream() .filter(PersonalData.class::isInstance) .map(PersonalData.class::cast) .map(PersonalData::getDataReferences) .flatMap(List::stream) .toList()); - result.addAll(storing.getOutputData()); - result.addAll(storing.getOutputData() + result.addAll(processing.getOutputData()); + result.addAll(processing.getOutputData() .stream() .filter(PersonalData.class::isInstance) .map(PersonalData.class::cast) .map(PersonalData::getDataReferences) .flatMap(List::stream) .toList()); - result.addAll(storing.getPurpose()); - result.addAll(storing.getOnTheBasisOf()); - result.add(storing.getResponsible()); + result.addAll(processing.getPurpose()); + result.addAll(processing.getOnTheBasisOf()); + result.add(processing.getResponsible()); } return result; } - private List determineContextDependentAttributes(DFDTransposeFlowGraph transposeFlowGraph, - Collection vertices) { + /** + * Determines the context dependent attribute sources for the given collection of vertices using the {@link mdpa.gdpr.analysis.core.TransformationManager} + * @param vertices List of vertices of which the {@link ContextDependentAttributeSource}s should be determined + * @return List of {@link ContextDependentAttributeSource} that are applicable to the given list of vertices + */ + private List determineContextDependentAttributes(Collection vertices) { if (!(this.resourceProvider instanceof GDPRResourceProvider gdprResourceProvider)) { this.logger.error("Resource provider is not a GDPR resource provider!"); throw new IllegalArgumentException(); @@ -237,6 +231,12 @@ private List determineContextDependentAttribute .toList(); } + /** + * Returns the flow graph collection that contains the final flow graph with resolved context dependent attributes. + *

+ * Note: This will create a new instance of the {@link DFDGDPRFlowGraphCollection} + * @return Returns a new {@link DFDGDPRFlowGraphCollection} containing the resolved {@link DFDGDPRTransposeFlowGraph}s + */ public DFDGDPRFlowGraphCollection resolveContextDependentAttributes() { List resultingTransposeFlowGraphs = this.getTransposeFlowGraphs() .stream() diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java index 40e6232..4219f32 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java @@ -63,7 +63,7 @@ public List determineAlternateFlowGraphs() { List states = ContextAttributeState.createAllContextAttributeStates(this.relevantContextDependentAttributes); Map, List> unmatchedStates = new HashMap<>(); for (ContextAttributeState state : states) { - if (state.getSelectedScenarios() + if (state.selectedScenarios() .stream() .noneMatch(it -> it.applicable(this))) { logger.warn("State not applicable to transpose flow graph, skipping"); @@ -71,7 +71,7 @@ public List determineAlternateFlowGraphs() { } DFDGDPRTransposeFlowGraph currentTransposeFlowGraph = (DFDGDPRTransposeFlowGraph) this.copy(new HashMap<>(), state); - for (ContextDependentAttributeScenario scenario : state.getSelectedScenarios()) { + for (ContextDependentAttributeScenario scenario : state.selectedScenarios()) { ContextDependentAttributeSource source = scenario.getContextDependentAttributeSource(); Optional matchingVertex = currentTransposeFlowGraph.getVertices() .stream() diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DataFlowDiagramAndDataDictionary.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DataFlowDiagramAndDataDictionary.java index 8f037e5..cdbd856 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DataFlowDiagramAndDataDictionary.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DataFlowDiagramAndDataDictionary.java @@ -1,28 +1,13 @@ package mdpa.gdpr.analysis.dfd; -import java.io.IOException; -import java.util.Map; import org.dataflowanalysis.dfd.datadictionary.DataDictionary; import org.dataflowanalysis.dfd.dataflowdiagram.DataFlowDiagram; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; +/** + * Contains a full metamodel required to run a DFD-based {@link org.dataflowanalysis.analysis.DataFlowConfidentialityAnalysis} + * @param dataFlowDiagram Data Flow Diagram of the model + * @param dataDictionary Data Dictionary of the model + */ public record DataFlowDiagramAndDataDictionary(DataFlowDiagram dataFlowDiagram, DataDictionary dataDictionary) { - public void save(String path) { - URI uriDFD = URI.createURI(path + "test.dataflowdiagram"); - URI uriDD = URI.createURI(path + "test.datadictionary"); - Resource resourceDFD = new XMIResourceImpl(uriDFD); - resourceDFD.getContents() - .add(dataFlowDiagram); - Resource resourceDD = new XMIResourceImpl(uriDD); - resourceDD.getContents() - .add(dataDictionary); - try { - resourceDFD.save(Map.of()); - resourceDD.save(Map.of()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + } diff --git a/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TrainModelEvaluation.java b/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TrainModelEvaluation.java index 9fcc6cf..fdc83b2 100644 --- a/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TrainModelEvaluation.java +++ b/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TrainModelEvaluation.java @@ -46,7 +46,7 @@ public void testImpactAmount() { .map(DFDGDPRTransposeFlowGraph.class::cast) .toList()) { List impactScenarios = transposeFlowGraph.getContextAttributeState() - .getSelectedScenarios() + .selectedScenarios() .stream() .toList(); var impactedElements = this.getImpactedElements(transposeFlowGraph, impactScenarios); diff --git a/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TravelPlannerEvaluation.java b/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TravelPlannerEvaluation.java index 75f76ca..ef79a08 100644 --- a/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TravelPlannerEvaluation.java +++ b/tests/mdpa.gdpr.analysis.tests/src/mdpa/gdpr/analysis/tests/validation/TravelPlannerEvaluation.java @@ -46,7 +46,7 @@ public void testImpactAmount() { .map(DFDGDPRTransposeFlowGraph.class::cast) .toList()) { List impactScenarios = transposeFlowGraph.getContextAttributeState() - .getSelectedScenarios() + .selectedScenarios() .stream() .filter(it -> !it.getName() .equals("UserNecessity")) @@ -104,7 +104,7 @@ public void testViolations() { continue; } var sourcesString = flowGraph.getContextAttributeState() - .getSelectedScenarios() + .selectedScenarios() .stream() .map(it -> it.getName()) .collect(Collectors.joining(",")); From fcad3d96a708dc2fcdc33ed27743faf02d9dae65 Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Mon, 22 Sep 2025 11:27:38 +0200 Subject: [PATCH 3/5] refactor(core): refacor duplicate code in transpose flow graph --- .../mdpa/gdpr/analysis/UncertaintyUtils.java | 58 ++++++++---------- .../dfd/DFDGDPRTransposeFlowGraph.java | 61 ++++++------------- 2 files changed, 43 insertions(+), 76 deletions(-) diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java index d1bee40..36239fd 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java @@ -4,6 +4,7 @@ import java.util.List; import mdpa.gdpr.analysis.core.ContextDependentAttributeScenario; import mdpa.gdpr.analysis.core.ContextDependentAttributeSource; +import mdpa.gdpr.analysis.dfd.DFDGDPRTransposeFlowGraph; import mdpa.gdpr.analysis.dfd.DFDGDPRVertex; import mdpa.gdpr.metamodel.GDPR.Data; import mdpa.gdpr.metamodel.GDPR.NaturalPerson; @@ -68,23 +69,7 @@ public static Behavior createBehavior(DFDGDPRVertex impactedElement, DataDiction .map(it -> EcoreUtil.copy(it)) .toList()); - LabelType type = dd.getLabelTypes() - .stream() - .filter(it -> it.getEntityName() - .equals(source.getPropertyType() - .getEntityName())) - .findAny() - .orElseThrow(); - List

* Note: Do not create an instance of this class manually, use the {@link GDPRLegalAssessmentAnalysisBuilder} instead - * @param resourceProvider {@link GDPRResourceProvider} providing a metamodel instance of the GDPR and Context Property model + * @param resourceProvider {@link GDPRResourceProvider} providing a metamodel instance of the GDPR and Context Property + * model * @param modelProjectActivator Optional model project activator * @param modelProjectName Optional model project name */ diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java index 61849d5..baae828 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/GDPRLegalAssessmentAnalysisBuilder.java @@ -10,9 +10,8 @@ /** * Extension of the {@link DataFlowAnalysisBuilder} responsible for creating a valid {@link GDPRLegalAssessmentAnalysis} - * from the following: - * - A valid path to a .gdpr metamodel instance - * - A valid path to a .contextproperties metamodel instance + * from the following: - A valid path to a .gdpr metamodel instance - A valid path to a .contextproperties metamodel + * instance */ public class GDPRLegalAssessmentAnalysisBuilder extends DataFlowAnalysisBuilder { private final Logger logger = Logger.getLogger(GDPRLegalAssessmentAnalysisBuilder.class); diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java index 36239fd..8051b62 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/UncertaintyUtils.java @@ -2,9 +2,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import mdpa.gdpr.analysis.core.ContextDependentAttributeScenario; import mdpa.gdpr.analysis.core.ContextDependentAttributeSource; -import mdpa.gdpr.analysis.dfd.DFDGDPRTransposeFlowGraph; import mdpa.gdpr.analysis.dfd.DFDGDPRVertex; import mdpa.gdpr.metamodel.GDPR.Data; import mdpa.gdpr.metamodel.GDPR.NaturalPerson; @@ -181,17 +181,19 @@ public static Behavior createBehavior(DFDGDPRVertex impactedElement, DataDiction List

* As a Context Dependent Attribute Scenario can occur in two scenarios we differentiate: - * */ public class ContextDependentAttributeScenario { private final Logger logger = Logger.getLogger(ContextDependentAttributeScenario.class); @@ -27,8 +26,8 @@ public class ContextDependentAttributeScenario { private final boolean resolvedUncertainty; /** - * Creates a new context dependent attribute scenario that matches a specific context. - * Therefore, it does not resolve an uncertain CDA + * Creates a new context dependent attribute scenario that matches a specific context. Therefore, it does not resolve an + * uncertain CDA * @param contextAnnotation {@link ContextAnnotation} the Scenario requires * @param contextDependentAttributeSource Corresponding {@link ContextDependentAttributeSource} */ @@ -42,9 +41,9 @@ public ContextDependentAttributeScenario(ContextAnnotation contextAnnotation, Co } /** - * Creates a new {@link ContextDependentAttributeScenario} that is resolving an uncertainty. - * Therefore, it requires a property value that is applied, the corresponding {@link ContextDependentAttributeSource} - * and a list of other {@link ContextDependentAttributeSource} that contradict the uncertain CDA + * Creates a new {@link ContextDependentAttributeScenario} that is resolving an uncertainty. Therefore, it requires a + * property value that is applied, the corresponding {@link ContextDependentAttributeSource} and a list of other + * {@link ContextDependentAttributeSource} that contradict the uncertain CDA * @param propertyValue Property value that is applied, when this scenario is applied * @param contextDependentAttributeSource Corresponding {@link ContextDependentAttributeSource} * @param sources Other {@link ContextDependentAttributeSource} that must not be true @@ -62,8 +61,7 @@ public ContextDependentAttributeScenario(PropertyValue propertyValue, ContextDep /** * Returns whether the {@link ContextDependentAttributeScenario} is applicable to the given vertex * @param vertex {@link DFDGDPRVertex} that is checked - * @return Returns true, if the scenario should be applied to the vertex. - * Otherwise, the method returns false + * @return Returns true, if the scenario should be applied to the vertex. Otherwise, the method returns false */ public boolean applicable(DFDGDPRVertex vertex) { logger.trace("Determining whether " + this.name + " can be applied to " + vertex); @@ -88,10 +86,11 @@ public boolean applicable(DFDGDPRVertex vertex) { } /** - * Determines whether the {@link ContextDependentAttributeScenario} is applicable to any of the nodes in the given transpose flow graph + * Determines whether the {@link ContextDependentAttributeScenario} is applicable to any of the nodes in the given + * transpose flow graph * @param transposeFlowGraph {@link DFDGDPRTransposeFlowGraph} that is checked - * @return Returns true, if the {@link ContextDependentAttributeScenario} can be applied to any of the vertices in the TFG. - * Otherwise, the method returns false + * @return Returns true, if the {@link ContextDependentAttributeScenario} can be applied to any of the vertices in the + * TFG. Otherwise, the method returns false */ public boolean applicable(DFDGDPRTransposeFlowGraph transposeFlowGraph) { if (this.resolvedUncertainty) { diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java index bd6d7e7..86c15f6 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/ContextDependentAttributeSource.java @@ -12,8 +12,8 @@ import mdpa.gdpr.metamodel.contextproperties.PropertyValue; /** - * This class models an application of a context dependent attribute on an element in the GDPR model. - * The different values it can take are saved in one or multiple child {@link ContextDependentAttributeScenario}. + * This class models an application of a context dependent attribute on an element in the GDPR model. The different + * values it can take are saved in one or multiple child {@link ContextDependentAttributeScenario}. */ public class ContextDependentAttributeSource { private final String name; @@ -26,8 +26,9 @@ public class ContextDependentAttributeSource { private final boolean resolvedUncertainty; /** - * Creates a new {@link ContextDependentAttributeSource} with the given property annotation containing the information about the annotated element and value - * and the context annotation describing the context of the {@link ContextDependentAttributeSource} + * Creates a new {@link ContextDependentAttributeSource} with the given property annotation containing the information + * about the annotated element and value and the context annotation describing the context of the + * {@link ContextDependentAttributeSource} * @param propertyAnnotation {@link PropertyAnnotation} describing where the CDA is applied * @param contextAnnotation {@link ContextAnnotation} describing which scenarios the source has */ @@ -42,10 +43,10 @@ public ContextDependentAttributeSource(PropertyAnnotation propertyAnnotation, Co } /** - * Creates a new {@link ContextDependentAttributeSource} that needs to be resolved with uncertain CDAs. - * Resolves an uncertainty regarding the value of an {@link ContextDependentAttributeSource} by creating a scenario for each - * passed {@link PropertyValue}. - * Additionally, the given list of other {@link ContextDependentAttributeSource} denotes where this source cannot apply + * Creates a new {@link ContextDependentAttributeSource} that needs to be resolved with uncertain CDAs. Resolves an + * uncertainty regarding the value of an {@link ContextDependentAttributeSource} by creating a scenario for each passed + * {@link PropertyValue}. Additionally, the given list of other {@link ContextDependentAttributeSource} denotes where + * this source cannot apply * @param propertyAnnotation {@link PropertyAnnotation} containing information about the annotated element and value * @param values Different {@link PropertyValue} that are resolved by the uncertainty * @param sources List of {@link ContextDependentAttributeSource} that cannot be applied at the same time @@ -67,7 +68,7 @@ public ContextDependentAttributeSource(PropertyAnnotation propertyAnnotation, Li * Determines whether this {@link ContextDependentAttributeSource} is applicable to the given list of vertices * @param vertices Given list of vertices * @return Returns true, if this {@link ContextDependentAttributeSource} is applicable at least one of the vertices - * Otherwise, the method returns false. + * Otherwise, the method returns false. */ public boolean applicable(Collection vertices) { if (!vertices.stream() @@ -84,12 +85,11 @@ public boolean applicable(Collection vertices) { /** * Determines whether the {@link ContextDependentAttributeSource} is applicable at the given vertex. *

- * This is the case, it the vertex has the annotated element in its context. - * If this {@link ContextDependentAttributeSource} is resolving an uncertainty, the other saved sources must not match. - * If this source is not resolving an uncertainty, it must match at least one context definition + * This is the case, it the vertex has the annotated element in its context. If this + * {@link ContextDependentAttributeSource} is resolving an uncertainty, the other saved sources must not match. If this + * source is not resolving an uncertainty, it must match at least one context definition * @param vertex Given {@link DFDGDPRVertex} that is checked - * @return Returns true, if the source is applicable to the vertex. - * Otherwise, the method returns false + * @return Returns true, if the source is applicable to the vertex. Otherwise, the method returns false */ public boolean applicable(DFDGDPRVertex vertex) { if (!vertex.getRelatedElements() diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java index 217c442..81bcaa1 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/TransformationManager.java @@ -22,7 +22,8 @@ import org.dataflowanalysis.dfd.dataflowdiagram.Node; /** - * Manages the transformation from GDPR to DFD that is required to find {@link org.dataflowanalysis.analysis.core.AbstractTransposeFlowGraph} for the analysis. + * Manages the transformation from GDPR to DFD that is required to find + * {@link org.dataflowanalysis.analysis.core.AbstractTransposeFlowGraph} for the analysis. */ public class TransformationManager { private final Logger logger = Logger.getLogger(TransformationManager.class); @@ -53,8 +54,8 @@ public DataFlowDiagramAndDataDictionary transform(LegalAssessmentFacts gdprModel } /** - * Runs some postprocessing on the resulting DFD model for keeping track of the trace between nodes and processing elements - * TODO: This can be replaced with the tracemodel + * Runs some postprocessing on the resulting DFD model for keeping track of the trace between nodes and processing + * elements TODO: This can be replaced with the tracemodel * @param dataFlowDiagram Data flow diagram of the Transformation * @param gdprModel GDPR model of the transformation */ @@ -72,8 +73,8 @@ private void processTransformation(DataFlowDiagram dataFlowDiagram, LegalAssessm } /** - * Creates the {@link ContextDependentAttributeSource}s and {@link ContextDependentAttributeScenario} for the context property model. - * Additionally, it creates the required labels in the data dictionary. + * Creates the {@link ContextDependentAttributeSource}s and {@link ContextDependentAttributeScenario} for the context + * property model. Additionally, it creates the required labels in the data dictionary. * @param propertyModel Context Property Model of the transformation * @param dataDictionary Data Dictionary of the transformation */ diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java index ab1ebd8..b697ea0 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRResourceProvider.java @@ -9,7 +9,8 @@ import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; /** - * A {@link ResourceProvider} providing the necessary resources to run a {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} + * A {@link ResourceProvider} providing the necessary resources to run a + * {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} */ public abstract class GDPRResourceProvider extends ResourceProvider { @Override @@ -28,13 +29,13 @@ public void setupResources() { /** * Returns the loaded GDPR model - * * @return Returns the GDPR model that is loaded by the resource provider */ public abstract LegalAssessmentFacts getGDPRModel(); /** - * Returns the {@link ContextDependentProperties} metamodel that is required to run a {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} + * Returns the {@link ContextDependentProperties} metamodel that is required to run a + * {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} * @return Returns the loaded Context Property model */ public abstract ContextDependentProperties getContextDependentProperties(); diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java index 64af96a..8b069f8 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/core/resource/GDPRURIResourceProvider.java @@ -22,7 +22,8 @@ public class GDPRURIResourceProvider extends GDPRResourceProvider { /** * Creates a new {@link GDPRURIResourceProvider} using the provided URIs to the models *

- * Usually, the resource provider will be created automatically when using {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysisBuilder} + * Usually, the resource provider will be created automatically when using + * {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysisBuilder} * @param modelURI URI path to the GDPR model * @param propertyURI URI path to the context property model */ diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java index 724302e..3c43656 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRFlowGraphCollection.java @@ -23,7 +23,8 @@ import org.dataflowanalysis.dfd.datadictionary.Pin; /** - * Models a collection of {@link DFDGDPRTransposeFlowGraph}s for use with the {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} + * Models a collection of {@link DFDGDPRTransposeFlowGraph}s for use with the + * {@link mdpa.gdpr.analysis.GDPRLegalAssessmentAnalysis} */ public class DFDGDPRFlowGraphCollection extends FlowGraphCollection { private final Logger logger = Logger.getLogger(DFDGDPRFlowGraphCollection.class); @@ -38,7 +39,8 @@ public DFDGDPRFlowGraphCollection(ResourceProvider resourceProvider) { } /** - * Creates a new {@link DFDGDPRFlowGraphCollection} with the given list of transpose flow graphs and a given resource provider + * Creates a new {@link DFDGDPRFlowGraphCollection} with the given list of transpose flow graphs and a given resource + * provider * @param transposeFlowGraphs List of {@link DFDGDPRTransposeFlowGraph}s that are stored in the flow graph collection * @param resourceProvider {@link ResourceProvider} that has the relevant model elements loaded */ @@ -64,8 +66,9 @@ public List findTransposeFlowGraphs() { } /** - * Finds the partial responsibility flow graphs for the contained flow graphs and creates a new {@link DFDGDPRFlowGraphCollection} - * containing the previous {@link DFDGDPRTransposeFlowGraph} with the additional partial responsibility flow graphs + * Finds the partial responsibility flow graphs for the contained flow graphs and creates a new + * {@link DFDGDPRFlowGraphCollection} containing the previous {@link DFDGDPRTransposeFlowGraph} with the additional + * partial responsibility flow graphs * @return Returns a new {@link DFDGDPRFlowGraphCollection} containing additional partial responsibility flow graphs */ public DFDGDPRFlowGraphCollection findResponsibilityFlowGraphs() { @@ -75,11 +78,11 @@ public DFDGDPRFlowGraphCollection findResponsibilityFlowGraphs() { .map(DFDGDPRTransposeFlowGraph.class::cast) .toList(); List flowGraphs = new ArrayList<>(completeFlowGraphs); - flowGraphs.addAll(completeFlowGraphs.stream() - .map(this::getPartialTransposeFlowGraphs) - .flatMap(List::stream) - .toList()); - return new DFDGDPRFlowGraphCollection(flowGraphs, this.resourceProvider); + flowGraphs.addAll(completeFlowGraphs.stream() + .map(this::getPartialTransposeFlowGraphs) + .flatMap(List::stream) + .toList()); + return new DFDGDPRFlowGraphCollection(flowGraphs, this.resourceProvider); } /** @@ -215,7 +218,8 @@ private List determineRelatedElements(AbstractGDPRElement g } /** - * Determines the context dependent attribute sources for the given collection of vertices using the {@link mdpa.gdpr.analysis.core.TransformationManager} + * Determines the context dependent attribute sources for the given collection of vertices using the + * {@link mdpa.gdpr.analysis.core.TransformationManager} * @param vertices List of vertices of which the {@link ContextDependentAttributeSource}s should be determined * @return List of {@link ContextDependentAttributeSource} that are applicable to the given list of vertices */ diff --git a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java index ad5245c..1e48b06 100644 --- a/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java +++ b/bundles/mdpa.gdpr.analysis/src/mdpa/gdpr/analysis/dfd/DFDGDPRTransposeFlowGraph.java @@ -14,7 +14,6 @@ import mdpa.gdpr.metamodel.GDPR.Data; import mdpa.gdpr.metamodel.GDPR.NaturalPerson; import mdpa.gdpr.metamodel.GDPR.PersonalData; -import mdpa.gdpr.metamodel.contextproperties.PropertyValue; import org.apache.log4j.Logger; import org.dataflowanalysis.analysis.core.AbstractTransposeFlowGraph; import org.dataflowanalysis.analysis.core.AbstractVertex; @@ -23,7 +22,6 @@ import org.dataflowanalysis.dfd.datadictionary.Behavior; import org.dataflowanalysis.dfd.datadictionary.DataDictionary; import org.dataflowanalysis.dfd.datadictionary.Label; -import org.dataflowanalysis.dfd.datadictionary.LabelType; import org.dataflowanalysis.dfd.datadictionary.Pin; import org.dataflowanalysis.dfd.dataflowdiagram.Node; import org.eclipse.emf.ecore.util.EcoreUtil; @@ -31,7 +29,7 @@ public class DFDGDPRTransposeFlowGraph extends DFDTransposeFlowGraph { private final Logger logger = Logger.getLogger(DFDGDPRTransposeFlowGraph.class); private final List relevantContextDependentAttributes; - private final DataDictionary dd; + private final DataDictionary dataDictionary; private final Optional contextAttributeState; @@ -39,11 +37,12 @@ public class DFDGDPRTransposeFlowGraph extends DFDTransposeFlowGraph { * Creates a new dfd transpose flow graph with the given sink that induces the transpose flow graph * @param sink Sink vertex that induces the transpose flow graph */ - public DFDGDPRTransposeFlowGraph(AbstractVertex sink, List contextDependentAttributes, DataDictionary dd) { + public DFDGDPRTransposeFlowGraph(AbstractVertex sink, List contextDependentAttributes, + DataDictionary dataDictionary) { super(sink); this.relevantContextDependentAttributes = contextDependentAttributes; this.contextAttributeState = Optional.empty(); - this.dd = dd; + this.dataDictionary = dataDictionary; } /** @@ -51,17 +50,16 @@ public DFDGDPRTransposeFlowGraph(AbstractVertex sink, List sink, List contextDependentAttributes, - ContextAttributeState contextAttributeState, DataDictionary dd) { + ContextAttributeState contextAttributeState, DataDictionary dataDictionary) { super(sink); this.relevantContextDependentAttributes = contextDependentAttributes; this.contextAttributeState = Optional.of(contextAttributeState); - this.dd = dd; + this.dataDictionary = dataDictionary; } public List determineAlternateFlowGraphs() { List result = new ArrayList<>(); List states = ContextAttributeState.createAllContextAttributeStates(this.relevantContextDependentAttributes); - Map, List> unmatchedStates = new HashMap<>(); for (ContextAttributeState state : states) { if (state.selectedScenarios() .stream() @@ -72,148 +70,170 @@ public List determineAlternateFlowGraphs() { DFDGDPRTransposeFlowGraph currentTransposeFlowGraph = (DFDGDPRTransposeFlowGraph) this.copy(new HashMap<>(), state); for (ContextDependentAttributeScenario scenario : state.selectedScenarios()) { - ContextDependentAttributeSource source = scenario.getContextDependentAttributeSource(); - Optional matchingVertex = currentTransposeFlowGraph.getVertices() + currentTransposeFlowGraph = this.handleScenario(scenario, currentTransposeFlowGraph, state) + .orElse(currentTransposeFlowGraph); + } + result.add(currentTransposeFlowGraph); + } + return result; + } + + private Optional handleScenario(ContextDependentAttributeScenario scenario, + DFDGDPRTransposeFlowGraph currentTransposeFlowGraph, ContextAttributeState state) { + ContextDependentAttributeSource source = scenario.getContextDependentAttributeSource(); + Optional matchingVertex = currentTransposeFlowGraph.getVertices() + .stream() + .filter(DFDGDPRVertex.class::isInstance) + .map(DFDGDPRVertex.class::cast) + .filter(source::applicable) + .findFirst(); + if (matchingVertex.isEmpty()) { + logger.warn("Could not find matching vertex for context dependent attribute"); + return Optional.empty(); + } + if (!scenario.applicable(matchingVertex.get())) { + // Scenario must not be resolved by uncertainty + logger.warn("Scenario not applicable to vertex!"); + return Optional.empty(); + } + + if (source.getAnnotatedElement() instanceof NaturalPerson person) { + // Insert Data Characteristic + List targetedVertices = this.determineTargetedVertices(currentTransposeFlowGraph, scenario); + + for (DFDGDPRVertex targetVertex : targetedVertices) { + DFDGDPRVertex currentTargetVertex = currentTransposeFlowGraph.getVertices() .stream() .filter(DFDGDPRVertex.class::isInstance) .map(DFDGDPRVertex.class::cast) - .filter(source::applicable) - .findFirst(); - if (matchingVertex.isEmpty()) { - logger.warn("Could not find matching vertex for context dependent attribute"); - continue; - } - if (!scenario.applicable(matchingVertex.get())) { - // Scenario must not be resolved by uncertainty - logger.warn("Scenario not applicable to vertex!"); - continue; - } - - if (source.getAnnotatedElement() instanceof NaturalPerson person) { - // Insert Data Characteristic - List targetedVertices = this.determineTargetedVertices(currentTransposeFlowGraph, scenario);; - - for (DFDGDPRVertex targetVertex : targetedVertices) { - DFDGDPRVertex currentTargetVertex = currentTransposeFlowGraph.getVertices() - .stream() - .filter(DFDGDPRVertex.class::isInstance) - .map(DFDGDPRVertex.class::cast) - .filter(it -> it.getReferencedElement() - .getId() - .equals(targetVertex.getReferencedElement() - .getId())) - .filter(it -> it.getReferencedElement() - .getEntityName() - .equals(targetVertex.getReferencedElement() - .getEntityName())) - .findAny() - .orElseThrow(); - DFDGDPRVertex impactedElement = currentTargetVertex.getPreviousElements() - .stream() - .filter(DFDGDPRVertex.class::isInstance) - .map(DFDGDPRVertex.class::cast) - .filter(it -> { - return it.getOutgoingData() - .stream() - .filter(PersonalData.class::isInstance) - .map(PersonalData.class::cast) - .anyMatch(data -> data.getDataReferences() - .contains(person)); - }) - .findAny() - .orElse(currentTargetVertex); - Behavior replacingBehavior = UncertaintyUtils.createBehavior(impactedElement, dd, source, scenario, person); - Node replacingNode = EcoreUtil.copy(impactedElement.getReferencedElement()); - replacingNode.setBehavior(replacingBehavior); - DFDGDPRVertex replacingVertex = this.copyVertex(impactedElement, replacingNode); - List scenarios = new ArrayList<>(impactedElement.getContextDependentAttributes()); - scenarios.add(scenario); - replacingVertex.setContextDependentAttributes(scenarios); - Map mapping = new HashMap<>(); - mapping.put(impactedElement, replacingVertex); - currentTransposeFlowGraph = (DFDGDPRTransposeFlowGraph) currentTransposeFlowGraph.copy(mapping, state); - } + .filter(it -> it.getReferencedElement() + .getId() + .equals(targetVertex.getReferencedElement() + .getId())) + .filter(it -> it.getReferencedElement() + .getEntityName() + .equals(targetVertex.getReferencedElement() + .getEntityName())) + .findAny() + .orElseThrow(); + DFDGDPRVertex impactedElement = currentTargetVertex.getPreviousElements() + .stream() + .filter(DFDGDPRVertex.class::isInstance) + .map(DFDGDPRVertex.class::cast) + .filter(it -> { + return it.getOutgoingData() + .stream() + .filter(PersonalData.class::isInstance) + .map(PersonalData.class::cast) + .anyMatch(data -> data.getDataReferences() + .contains(person)); + }) + .findAny() + .orElse(currentTargetVertex); + Behavior replacingBehavior = UncertaintyUtils.createBehavior(impactedElement, dataDictionary, source, scenario, person); + Node replacingNode = EcoreUtil.copy(impactedElement.getReferencedElement()); + replacingNode.setBehavior(replacingBehavior); + DFDGDPRVertex replacingVertex = this.copyVertex(impactedElement, replacingNode); + List scenarios = new ArrayList<>(impactedElement.getContextDependentAttributes()); + scenarios.add(scenario); + replacingVertex.setContextDependentAttributes(scenarios); + Map mapping = new HashMap<>(); + mapping.put(impactedElement, replacingVertex); + currentTransposeFlowGraph = (DFDGDPRTransposeFlowGraph) currentTransposeFlowGraph.copy(mapping, state); + } + return Optional.of(currentTransposeFlowGraph); - } else if (source.getAnnotatedElement() instanceof Data data) { - // Insert Data Characteristic - List targetedVertices = this.determineTargetedVertices(currentTransposeFlowGraph, scenario);; - for (DFDGDPRVertex targetVertex : targetedVertices) { - DFDGDPRVertex currentTargetVertex = currentTransposeFlowGraph.getVertices() - .stream() - .filter(DFDGDPRVertex.class::isInstance) - .map(DFDGDPRVertex.class::cast) - .filter(it -> it.getReferencedElement() - .getId() - .equals(targetVertex.getReferencedElement() - .getId())) - .filter(it -> it.getReferencedElement() - .getEntityName() - .equals(targetVertex.getReferencedElement() - .getEntityName())) - .findAny() - .orElseThrow(); - DFDGDPRVertex impactedElement = currentTargetVertex.getPreviousElements() - .stream() - .filter(DFDGDPRVertex.class::isInstance) - .map(DFDGDPRVertex.class::cast) - .filter(it -> it.getOutgoingData() - .contains(data)) - .findAny() - .orElse(currentTargetVertex); - Behavior replacingBehavior = UncertaintyUtils.createBehavior(impactedElement, dd, source, scenario, data); - Node replacingNode = EcoreUtil.copy(impactedElement.getReferencedElement()); - replacingNode.setBehavior(replacingBehavior); - DFDGDPRVertex replacingVertex = this.copyVertex(impactedElement, replacingNode); - List scenarios = new ArrayList<>(impactedElement.getContextDependentAttributes()); - scenarios.add(scenario); - replacingVertex.setContextDependentAttributes(scenarios); - Map mapping = new HashMap<>(); - mapping.put(impactedElement, replacingVertex); - currentTransposeFlowGraph = (DFDGDPRTransposeFlowGraph) currentTransposeFlowGraph.copy(mapping, state); - } - } else { - // Insert Node Characteristics at all matching vertices - List matchingVertices = currentTransposeFlowGraph.getVertices() - .stream() - .filter(DFDGDPRVertex.class::isInstance) - .map(DFDGDPRVertex.class::cast) - .filter(source::applicable) - .filter(scenario::applicable) - .map(it -> it.getReferencedElement() - .getId()) - .toList(); - for (String targetVertexID : matchingVertices) { - DFDGDPRVertex targetVertex = currentTransposeFlowGraph.getVertices() - .stream() - .filter(DFDGDPRVertex.class::isInstance) - .map(DFDGDPRVertex.class::cast) - .filter(it -> it.getReferencedElement() - .getId() - .equals(targetVertexID)) - .findFirst() - .orElseThrow(); - Node replacingNode = EcoreUtil.copy(targetVertex.getReferencedElement()); + } else if (source.getAnnotatedElement() instanceof Data data) { + // Insert Data Characteristic + List targetedVertices = this.determineTargetedVertices(currentTransposeFlowGraph, scenario); + ; + for (DFDGDPRVertex targetVertex : targetedVertices) { + DFDGDPRVertex currentTargetVertex = currentTransposeFlowGraph.getVertices() + .stream() + .filter(DFDGDPRVertex.class::isInstance) + .map(DFDGDPRVertex.class::cast) + .filter(it -> it.getReferencedElement() + .getId() + .equals(targetVertex.getReferencedElement() + .getId())) + .filter(it -> it.getReferencedElement() + .getEntityName() + .equals(targetVertex.getReferencedElement() + .getEntityName())) + .findAny() + .orElseThrow(); + DFDGDPRVertex impactedElement = currentTargetVertex.getPreviousElements() + .stream() + .filter(DFDGDPRVertex.class::isInstance) + .map(DFDGDPRVertex.class::cast) + .filter(it -> it.getOutgoingData() + .contains(data)) + .findAny() + .orElse(currentTargetVertex); + Behavior replacingBehavior = UncertaintyUtils.createBehavior(impactedElement, dataDictionary, source, scenario, data); + Node replacingNode = EcoreUtil.copy(impactedElement.getReferencedElement()); + replacingNode.setBehavior(replacingBehavior); + DFDGDPRVertex replacingVertex = this.copyVertex(impactedElement, replacingNode); + List scenarios = new ArrayList<>(impactedElement.getContextDependentAttributes()); + scenarios.add(scenario); + replacingVertex.setContextDependentAttributes(scenarios); + Map mapping = new HashMap<>(); + mapping.put(impactedElement, replacingVertex); + currentTransposeFlowGraph = (DFDGDPRTransposeFlowGraph) currentTransposeFlowGraph.copy(mapping, state); + } + return Optional.of(currentTransposeFlowGraph); + } else { + // Insert Node Characteristics at all matching vertices + List matchingVertices = currentTransposeFlowGraph.getVertices() + .stream() + .filter(DFDGDPRVertex.class::isInstance) + .map(DFDGDPRVertex.class::cast) + .filter(source::applicable) + .filter(scenario::applicable) + .map(it -> it.getReferencedElement() + .getId()) + .toList(); + for (String targetVertexID : matchingVertices) { + DFDGDPRVertex targetVertex = currentTransposeFlowGraph.getVertices() + .stream() + .filter(DFDGDPRVertex.class::isInstance) + .map(DFDGDPRVertex.class::cast) + .filter(it -> it.getReferencedElement() + .getId() + .equals(targetVertexID)) + .findFirst() + .orElseThrow(); + Node replacingNode = EcoreUtil.copy(targetVertex.getReferencedElement()); - List