Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.dataflowanalysis.analysis.dsl.selectors.AbstractSelector;
import org.dataflowanalysis.analysis.dsl.selectors.VertexCharacteristicsListSelector;
import org.dataflowanalysis.analysis.dsl.selectors.VertexCharacteristicsSelector;
import org.dataflowanalysis.analysis.dsl.selectors.VertexNameSelector;
import org.dataflowanalysis.analysis.dsl.selectors.VertexTypeSelector;
import org.dataflowanalysis.analysis.utils.ParseResult;
import org.dataflowanalysis.analysis.utils.StringView;
Expand Down Expand Up @@ -88,6 +89,11 @@ public static ParseResult<VertexDestinationSelectors> fromString(StringView stri
selectors.add(selector.getResult());
continue;
}
var nameSelector = VertexNameSelector.fromString(string, context);
if (nameSelector.successful()) {
selectors.add(nameSelector.getResult());
continue;
}
var typeSelector = VertexTypeSelector.fromString(string, context);
if (typeSelector.successful()) {
selectors.add(typeSelector.getResult());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ public DSLNodeDestinationSelector withoutCharacteristic(String characteristicTyp
return this;
}

/**
* Match vertices that have the given vertex name
* @param vertexName Name the given vertex should have
* @return DSL node selector to add more constraints
*/
public DSLNodeDestinationSelector withVertexName(String vertexName) {
this.analysisConstraint.addNodeDestinationSelector(new VertexNameSelector(vertexName, analysisConstraint.getContext()));
return this;
}

/**
* Match vertices that do not have the given vertex name
* @param vertexName Name the given vertex should not have
* @return DSL node selector to add more constraints
*/
public DSLNodeDestinationSelector withoutVertexName(String vertexName) {
this.analysisConstraint.addNodeDestinationSelector(new VertexNameSelector(vertexName, true, analysisConstraint.getContext()));
return this;
}

/**
* Match vertices that match the given predicate
* <p/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.dataflowanalysis.analysis.dsl.selectors;

import org.apache.log4j.Logger;
import org.dataflowanalysis.analysis.core.AbstractVertex;
import org.dataflowanalysis.analysis.dsl.context.DSLContext;
import org.dataflowanalysis.analysis.utils.ParseResult;
import org.dataflowanalysis.analysis.utils.StringView;
import org.palladiosimulator.pcm.core.entity.Entity;
import tools.mdsd.modelingfoundations.identifier.NamedElement;

public class VertexNameSelector extends VertexSelector {
private static final String DSL_KEYWORD = "named";
private static final Logger logger = Logger.getLogger(VertexNameSelector.class);

private final String name;
private final boolean inverted;

/**
* Create a new {@link VertexNameSelector} that matches vertices with the given name.
* @param name Name the vertex should have
* @param context Context of the DSL Selector
*/
public VertexNameSelector(String name, DSLContext context) {
super(context);
this.name = name;
this.inverted = false;
}

/**
* Create a new {@link VertexNameSelector} that matches vertices with the given name. Additionally, the inverted boolean
* denotes whether the selector is inverted or not
* @param name Name the vertex should (or should not) have
* @param inverted Denotes whether the selector should be inverted or not
* @param context Context of the DSL Selector
*/
public VertexNameSelector(String name, boolean inverted, DSLContext context) {
super(context);
this.name = name;
this.inverted = inverted;
}

@Override
public boolean matches(AbstractVertex<?> vertex) {
String vertexName;
if (vertex.getReferencedElement() instanceof NamedElement namedElement) {
vertexName = namedElement.getEntityName();
} else if (vertex.getReferencedElement() instanceof Entity pcmEntity) {
vertexName = pcmEntity.getEntityName();
} else {
return false;
}
return this.inverted ? !vertexName.equalsIgnoreCase(this.name) : vertexName.equalsIgnoreCase(this.name);
}

@Override
public String toString() {
return this.inverted ? DSL_INVERTED_SYMBOL + DSL_KEYWORD + " " + this.name : DSL_KEYWORD + " " + this.name;
}

/**
* Parses a {@link VertexNameSelector} object from the given view on a string
* <p/>
* This method expects the following format: {@code named <Name>}
* @param string String view on the string that is parsed
* @return {@link ParseResult} containing the {@link VertexNameSelector} object
*/
public static ParseResult<VertexNameSelector> fromString(StringView string, DSLContext context) {
string.skipWhitespace();
if (string.invalid() || string.empty()) {
return ParseResult.error("Cannot parse vertex name selector from empty or invalid string!");
}
logger.info("Parsing: " + string.getString());
int position = string.getPosition();
boolean inverted = false;
if (string.startsWith(DSL_INVERTED_SYMBOL)) {
string.advance(DSL_INVERTED_SYMBOL.length());
inverted = true;
}
if (!string.startsWith(DSL_KEYWORD)) {
return string.expect(DSL_KEYWORD);
}
string.advance(DSL_KEYWORD.length() + 1);
if (string.invalid() || string.empty()) {
string.setPosition(position);
return ParseResult.error("Cannot parse vertex name selector from empty or invalid string!");
}
String[] split = string.getString()
.split(" ");
if (split.length == 0 || split[0].isEmpty()) {
string.setPosition(position);
return ParseResult.error("Invalid vertex name in vertex name selector!");
}
string.advance(split[0].length());
string.advance(1);
return ParseResult.ok(new VertexNameSelector(split[0], inverted, context));
}
}
11 changes: 11 additions & 0 deletions docs/wiki/dsl/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ vertex Location.nonEU
```
:::

### Vertex Name Selector
A node can be selected according to it's name in the model, using the `named <Name>` selector, where `<Name>` is the name the vertex should have.
The specified name cannot contain any spaces.
Additionally, this selector can be inverted using `!named <Name>`.
::: tip Example
To match all vertices **exactly** named "Database", one might use the following selector:
```
named Database
```
:::

### Vertex Type Selector
Additionally, one might select nodes based on their type using the `vertex type <Type>` **source selector**.
The `<Type>` describes the model element the node must have to match the selector.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.dataflowanalysis.analysis.utils.ParseResult;
import org.dataflowanalysis.analysis.utils.StringView;
import org.junit.jupiter.api.Test;
import tools.mdsd.modelingfoundations.identifier.NamedElement;

public class DSLResultTest extends BaseTest {
private static final Logger logger = Logger.getLogger(DSLResultTest.class);
Expand Down Expand Up @@ -167,6 +168,39 @@ public void testDataLabelOr() {
.toString());
}

@Test
public void testNameSelector() {
AnalysisConstraint constraint = new ConstraintDSL().ofData()
.neverFlows()
.toVertex()
.withVertexName("DatabaseLoadInventory")
.create();

FlowGraphCollection flowGraph = onlineShopAnalysis.findFlowGraphs();
flowGraph.evaluate();
List<DSLResult> result = constraint.findViolations(flowGraph);
List<? extends AbstractVertex<?>> violations = result.stream()
.map(DSLResult::getMatchedVertices)
.flatMap(List::stream)
.toList();
for (AbstractVertex<?> vertex : violations) {
if (!(vertex instanceof NamedElement namedElement)) {
continue;
}
if (namedElement.getEntityName()
.equalsIgnoreCase("DatabaseLoadInventory")) {
continue;
}
logger.error("Should not have matched vertex: " + vertex.createPrintableNodeInformation());
}
logger.setLevel(Level.TRACE);
violations.forEach(vertex -> logger.trace(vertex.createPrintableNodeInformation()));
assertEquals(2 * 2, violations.size());
assertEquals(constraint.toString(), AnalysisConstraint.fromString(new StringView(constraint.toString()))
.getResult()
.toString());
}

private void evaluateAnalysis(AnalysisConstraint constraint, DataFlowConfidentialityAnalysis analysis, List<ConstraintData> expectedResults) {
logger.info("DSL String: " + constraint.toString());
ParseResult<AnalysisConstraint> constraintParsed = AnalysisConstraint.fromString(new StringView(constraint.toString()),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.dataflowanalysis.analysis.tests.integration.dsl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.stream.Stream;
import org.dataflowanalysis.analysis.dsl.context.DSLContext;
import org.dataflowanalysis.analysis.dsl.selectors.VariableNameSelector;
import org.dataflowanalysis.analysis.utils.ParseResult;
import org.dataflowanalysis.analysis.utils.StringView;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

public class VertexNameSelectorTest {
@ParameterizedTest
@MethodSource("correctVertexNameSelectors")
public void shouldParseCorrectly(String variableNameSelectorString, String expectedVariableName) {
ParseResult<VariableNameSelector> variableNameSelector = VariableNameSelector.fromString(new StringView(variableNameSelectorString),
new DSLContext());
assertTrue(variableNameSelector.successful());
assertEquals(expectedVariableName, variableNameSelector.getResult()
.getVariableName());
}

@ParameterizedTest
@MethodSource("incorrectVertexNameSelectors")
public void shouldNotParse(String variableNameSelectorString) {
ParseResult<VariableNameSelector> variableNameSelector = VariableNameSelector.fromString(new StringView(variableNameSelectorString),
new DSLContext());
assertTrue(variableNameSelector.failed());
}

private static Stream<Arguments> correctVertexNameSelectors() {
return Stream.of(Arguments.of("named name", "name"), Arguments.of("named otherA.otherB", "otherA.otherB"),
Arguments.of("named some string with spaces", "some"));
}

private static Stream<Arguments> incorrectVertexNameSelectors() {
return Stream.of(Arguments.of("named"), Arguments.of(""), Arguments.of("named "));
}
}