Skip to content

Commit

Permalink
Split DFD and Web Converter
Browse files Browse the repository at this point in the history
  • Loading branch information
uuqjz committed Oct 23, 2024
1 parent 85a9144 commit 788e830
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 336 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,15 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;


import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.dataflowanalysis.analysis.core.AbstractTransposeFlowGraph;
import org.dataflowanalysis.analysis.core.AbstractVertex;
Expand All @@ -46,39 +39,13 @@
public class DataFlowDiagramConverter extends Converter {

private Map<Pin, List<String>> inputPinToFlowNamesMap;
private final dataflowdiagramFactory dfdFactory;
private final datadictionaryFactory ddFactory;
private Map<String, Node> idToNodeMap;

private final Logger logger = Logger.getLogger(DataFlowDiagramConverter.class);
protected final static String DELIMITER_PIN_NAME = "|";
protected final static String DELIMITER_MULTI_PIN = ",";

private BehaviorConverter behaviorConverter;

public DataFlowDiagramConverter() {
dfdFactory = dataflowdiagramFactory.eINSTANCE;
ddFactory = datadictionaryFactory.eINSTANCE;
}

/**
* Converts a Web Editor DFD format file into a DataFlowDiagramAndDictionary object.
* @param inputFile The path of the input file in Web Editor DFD format.
* @return DataFlowDiagramAndDictionary object representing the converted data flow diagram and dictionary.
*/
public DataFlowDiagramAndDictionary webToDfd(String inputFile) {
return webToDfd(loadWeb(inputFile).get());
}

/**
* Converts a WebEditorDfd object into a DataFlowDiagramAndDictionary object.
* @param inputFile The WebEditorDfd object to convert.
* @return DataFlowDiagramAndDictionary object representing the converted data flow diagram and dictionary.
*/
public DataFlowDiagramAndDictionary webToDfd(WebEditorDfd inputFile) {
return processWeb(inputFile);
}

/**
* Converts Data Flow Diagram and Data Dictionary provided via paths into a WebEditorDfd object, analyzes it and annotates the propagated labels in the WebDFD.
* @param inputDataFlowDiagram The path of the data flow diagram.
Expand Down Expand Up @@ -149,8 +116,6 @@ public WebEditorDfd dfdToWebAndAnalyzeAndAnnotateWithCustomTFGFinder(DataFlowDia
return processDfd(complete.dataFlowDiagram(), complete.dataDictionary(), createNodeAnnotationMap(complete, conditions, finderClass));
}



/**
* Stores a WebEditorDfd object into a specified output file.
* @param web The WebEditorDfd object to store.
Expand All @@ -166,25 +131,7 @@ public void storeWeb(WebEditorDfd web, String outputFile) {
} catch (IOException e) {
logger.error("Could not store web dfd:", e);
}
}


/**
* Loads a WebEditorDfd object from a specified input file.
* @param inputFile The path of the input file.
* @return Optional containing the loaded WebEditorDfd object; empty if an error occurs.
*/
public Optional<WebEditorDfd> loadWeb(String inputFile) {
objectMapper = new ObjectMapper();
file = new File(inputFile);
try {
WebEditorDfd result = objectMapper.readValue(file, WebEditorDfd.class);
return Optional.ofNullable(result); // This will never be null given readValue's behavior, but it's a safe usage pattern.
} catch (IOException e) {
logger.error("Could not load web dfd:", e);
return Optional.empty();
}
}
}

/**
* Loads a data flow diagram and data dictionary from specified input files and returns them as a combined object.
Expand Down Expand Up @@ -269,169 +216,7 @@ private Map<Node, Annotation> createNodeAnnotationMap (DataFlowDiagramAndDiction
return mapNodeToAnnotations;
}

private DataFlowDiagramAndDictionary processWeb(WebEditorDfd webdfd) {
idToNodeMap = new HashMap<>();
Map<String, Node> pinToNodeMap = new HashMap<>();
Map<String, Pin> idToPinMap = new HashMap<>();
Map<String, Label> idToLabelMap = new HashMap<>();
Map<Node, Map<Pin, String>> nodeOutpinBehaviorMap = new HashMap<>();

DataFlowDiagram dataFlowDiagram = dfdFactory.createDataFlowDiagram();
DataDictionary dataDictionary = ddFactory.createDataDictionary();

behaviorConverter = new BehaviorConverter(dataDictionary);

createWebLabelTypes(webdfd, idToLabelMap, dataDictionary);

createWebNodes(webdfd, pinToNodeMap, idToPinMap, idToLabelMap, nodeOutpinBehaviorMap, dataFlowDiagram, dataDictionary);

createWebFlows(webdfd, pinToNodeMap, idToPinMap, dataFlowDiagram);

List<Node> nodesInBehavior = nodeOutpinBehaviorMap.keySet()
.stream()
.collect(Collectors.toList());

nodesInBehavior.forEach(node -> {
Map<Pin, String> outpinBehaviors = nodeOutpinBehaviorMap.get(node);
outpinBehaviors.forEach((outpin, behavior) -> {
parseBehavior(node, outpin, behavior, dataFlowDiagram, dataDictionary);
});
});

return new DataFlowDiagramAndDictionary(dataFlowDiagram, dataDictionary);
}

private void createWebNodes(WebEditorDfd webdfd, Map<String, Node> pinToNodeMap, Map<String, Pin> pinMap, Map<String, Label> idToLabelMap,
Map<Node, Map<Pin, String>> nodeOutpinBehavior, DataFlowDiagram dataFlowDiagram, DataDictionary dataDictionary) {
for (Child child : webdfd.model()
.children()) {
String[] type = child.type()
.split(":");
String name = child.text();

if (type[0].equals("node")) {
Node node = switch (type[1]) {
case "function" -> dfdFactory.createProcess();
case "storage" -> dfdFactory.createStore();
case "input-output" -> dfdFactory.createExternal();
default -> {
logger.error("Unrecognized node type: " + type[1]);
continue;
}
};

node.setEntityName(name);
node.setId(child.id());

var behaviour = ddFactory.createBehaviour();
behaviour.setEntityName(name);
node.setBehaviour(behaviour);
dataDictionary.getBehaviour()
.add(behaviour);

createWebPins(pinToNodeMap, pinMap, nodeOutpinBehavior, child, node);

List<Label> labelsAtNode = child.labels()
.stream()
.map(it -> idToLabelMap.get(it.labelTypeValueId()))
.toList();
node.getProperties()
.addAll(labelsAtNode);

dataFlowDiagram.getNodes()
.add(node);
idToNodeMap.put(child.id(), node);
}
}
}

private void createWebFlows(WebEditorDfd webdfd, Map<String, Node> pinToNodeMap, Map<String, Pin> pinMap, DataFlowDiagram dataFlowDiagram) {

webdfd.model()
.children()
.stream()
.filter(child -> child.type()
.contains("edge:"))
.forEach(child -> {
var source = pinToNodeMap.get(child.sourceId());
var dest = pinToNodeMap.get(child.targetId());

var flow = dfdFactory.createFlow();
flow.setSourceNode(source);
flow.setDestinationNode(dest);
flow.setEntityName(child.text());

var destPin = pinMap.get(child.targetId());
var sourcePin = pinMap.get(child.sourceId());

destPin.setEntityName(destPin.getEntityName() + child.text());
sourcePin.setEntityName(sourcePin.getEntityName() + child.text());

flow.setDestinationPin(destPin);
flow.setSourcePin(sourcePin);
flow.setId(child.id());
dataFlowDiagram.getFlows()
.add(flow);
});

}

private void createWebPins(Map<String, Node> pinToNodeMap, Map<String, Pin> pinMap, Map<Node, Map<Pin, String>> nodeOutpinBehavior, Child child,
Node node) {
for (Port port : child.ports()) {
switch (port.type()) {
case "port:dfd-input" -> pinMap.put(port.id(), createWebInPin(node, port));
case "port:dfd-output" -> pinMap.put(port.id(), createWebOutPin(nodeOutpinBehavior, node, port));
default -> logger.error("Unrecognized port type");
}
pinToNodeMap.put(port.id(), node);
}
}

private Pin createWebOutPin(Map<Node, Map<Pin, String>> nodeOutpinBehavior, Node node, Port port) {
var outPin = ddFactory.createPin();
outPin.setId(port.id());
outPin.setEntityName(node.getEntityName() + "_out_");
node.getBehaviour()
.getOutPin()
.add(outPin);
if (port.behavior() != null) {
putValue(nodeOutpinBehavior, node, outPin, port.behavior());
}
return outPin;
}

private Pin createWebInPin(Node node, Port port) {
var inPin = ddFactory.createPin();
inPin.setId(port.id());
inPin.setEntityName(node.getEntityName() + "_in_");
node.getBehaviour()
.getInPin()
.add(inPin);
return inPin;
}

private void createWebLabelTypes(WebEditorDfd webdfd, Map<String, Label> idToLabelMap, DataDictionary dataDictionary) {
for (WebEditorLabelType webLabelType : webdfd.labelTypes()) {
LabelType labelType = ddFactory.createLabelType();
labelType.setEntityName(webLabelType.name());
labelType.setId(webLabelType.id());
for (Value value : webLabelType.values()) {
createWebLabel(idToLabelMap, labelType, value);
}
dataDictionary.getLabelTypes()
.add(labelType);
}
}

private void createWebLabel(Map<String, Label> idToLabelMap, LabelType labelType, Value value) {
Label label = ddFactory.createLabel();
label.setEntityName(value.text());
label.setId(value.id());
labelType.getLabel()
.add(label);
idToLabelMap.put(label.getId(), label);
}

private void createLabelTypesAndValues(List<WebEditorLabelType> labelTypes, DataDictionary dataDictionary) {
for (LabelType labelType : dataDictionary.getLabelTypes()) {
Expand Down Expand Up @@ -505,11 +290,11 @@ private void createNodes(DataFlowDiagram dataFlowDiagram, List<Child> children,
private void createFlows(DataFlowDiagram dataFlowDiagram, List<Child> children) {
for (Flow flow : dataFlowDiagram.getFlows()) {
fillPinToFlowNamesMap(inputPinToFlowNamesMap,flow);
children.add(createWebFlow(flow));
children.add(createFlow(flow));
}
}

private Child createWebFlow(Flow flow) {
private Child createFlow(Flow flow) {
String id = flow.getId();
String type = "edge:arrow";
String sourceId = flow.getSourcePin()
Expand Down Expand Up @@ -584,73 +369,6 @@ private String getStringFromInputPins (List<Pin> inputPins) {
return String.join(DELIMITER_MULTI_PIN, pinNamesAsString);
}

private void parseBehavior(Node node, Pin outpin, String lines, DataFlowDiagram dfd, DataDictionary dd) {
String[] behaviorStrings = lines.split("\n");
var behavior = node.getBehaviour();
for (String behaviorString : behaviorStrings) {
behaviorString = behaviorString.replace(" ", "");
if (behaviorString.contains("Forwarding")) {
var assignment = ddFactory.createForwardingAssignment();
assignment.setOutputPin(outpin);

String regex = "^Forwarding\\(\\{([^}]*)\\}\\)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(behaviorString);
if (!matcher.matches()) {
logger.error("Invalid behavior string:");
logger.error(behaviorString);
continue;
}

assignment.getInputPins().addAll(getInPinsFromString(matcher.group(1), node, dfd));

behavior.getAssignment()
.add(assignment);
} else if (behaviorString.contains("Assignment")) {
String regex = "^Assignment\\(\\{([^}]*)\\};([^;]+);\\{([^}]*)\\}\\)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(behaviorString);
if (!matcher.matches()) {
logger.error("Invalid behavior string:");
logger.error(behaviorString);
continue;
}

String inPinsAsString = matcher.group(1);
String term = matcher.group(2);
String outLabelsAsString = matcher.group(3);

Assignment assignment = ddFactory.createAssignment();
assignment.setOutputPin(outpin);
assignment.setTerm(behaviorConverter.stringToTerm(term));
assignment.getInputPins().addAll(getInPinsFromString(inPinsAsString, node, dfd));

Arrays.asList(outLabelsAsString.split(",")).forEach(typeValuePair -> {
String typeName = typeValuePair.split("\\.")[0];
String valueName = typeValuePair.split("\\.")[1];

Label value = dd.getLabelTypes()
.stream()
.filter(labelType -> labelType.getEntityName()
.equals(typeName))
.flatMap(labelType -> labelType.getLabel()
.stream())
.filter(label -> label.getEntityName()
.equals(valueName))
.findAny()
.orElse(null);
assignment.getOutputLabels()
.add(value);
});

behavior.getAssignment()
.add(assignment);
}
}
}



private void fillPinToFlowNamesMap(Map<Pin,List<String>> map,Flow flow) {
if (map.containsKey(flow.getDestinationPin())) {
map.get(flow.getDestinationPin())
Expand All @@ -662,33 +380,4 @@ private void fillPinToFlowNamesMap(Map<Pin,List<String>> map,Flow flow) {
}
}

private void putValue(Map<Node, Map<Pin, String>> nestedHashMap, Node node, Pin pin, String value) {
nestedHashMap.computeIfAbsent(node, k -> new HashMap<>())
.put(pin, value);
}

private List<Pin> getInPinsFromString(String pinString, Node node, DataFlowDiagram dfd) {
List<Pin> inPins = new ArrayList<>();
List<String> pinNames = Arrays.asList(pinString.split(DELIMITER_MULTI_PIN + "\\s*"));

List<Flow> flowsToNode = dfd.getFlows()
.stream()
.filter(flow -> flow.getDestinationNode() == node)
.toList();

Map<Pin,List<String>>pinToFlowNames = new HashMap<>();
for (var flow : flowsToNode) {
fillPinToFlowNamesMap(pinToFlowNames,flow);
}

pinNames.forEach(pinName -> {
List<String> incomingFlowNames = Arrays.asList(pinName.split(Pattern.quote(DELIMITER_PIN_NAME)));
pinToFlowNames.keySet().forEach(key -> {
if (pinToFlowNames.get(key).containsAll(incomingFlowNames)) inPins.add(key);
});
});

return inPins;
}

}
Loading

0 comments on commit 788e830

Please sign in to comment.