-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add init builder impl for worker model
- Loading branch information
Showing
4 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
...odel-generator-core/src/main/java/io.ballerina.workermodelgenerator.core/FlowBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. | ||
* | ||
* WSO2 LLC. licenses this file to you under the Apache License, | ||
* Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
package io.ballerina.workermodelgenerator.core; | ||
|
||
import io.ballerina.compiler.api.SemanticModel; | ||
import io.ballerina.compiler.syntax.tree.BlockStatementNode; | ||
import io.ballerina.compiler.syntax.tree.NamedWorkerDeclarationNode; | ||
import io.ballerina.compiler.syntax.tree.NodeVisitor; | ||
import io.ballerina.workermodelgenerator.core.model.Flow; | ||
import io.ballerina.workermodelgenerator.core.model.FlowJsonBuilder; | ||
import io.ballerina.workermodelgenerator.core.model.WorkerNode; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** | ||
* Builder implementation for creating a {@link Flow} instance. | ||
* | ||
* @since 2201.9.0 | ||
*/ | ||
class FlowBuilder extends NodeVisitor implements FlowJsonBuilder { | ||
|
||
private String id; | ||
private String name; | ||
private String filePath; | ||
private final List<WorkerNode> nodes; | ||
private final SemanticModel semanticModel; | ||
|
||
public FlowBuilder(String id, String name, String filePath, SemanticModel semanticModel) { | ||
this.nodes = new ArrayList<>(); | ||
setId(id); | ||
setName(name); | ||
setFilePath(filePath); | ||
this.semanticModel = semanticModel; | ||
} | ||
|
||
@Override | ||
public void visit(NamedWorkerDeclarationNode namedWorkerDeclarationNode) { | ||
NodeBuilder nodeBuilder = new NodeBuilder(semanticModel); | ||
|
||
// Set the metadata information of the node | ||
nodeBuilder.setCodeLocation(namedWorkerDeclarationNode.lineRange().startLine(), | ||
namedWorkerDeclarationNode.lineRange().endLine()); | ||
nodeBuilder.setTemplateKind(TemplateKind.TRANSFORMER); | ||
|
||
// Analyze the body of the worker | ||
BlockStatementNode blockStatementNode = namedWorkerDeclarationNode.workerBody(); | ||
blockStatementNode.statements().forEach(statement -> statement.accept(nodeBuilder)); | ||
addNode(nodeBuilder.build()); | ||
} | ||
|
||
@Override | ||
public void setId(String id) { | ||
this.id = id; | ||
} | ||
|
||
@Override | ||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
@Override | ||
public void setFilePath(String filePath) { | ||
this.filePath = filePath; | ||
} | ||
|
||
@Override | ||
public void addNode(WorkerNode node) { | ||
this.nodes.add(node); | ||
} | ||
|
||
@Override | ||
public Flow build() { | ||
return new Flow(id, name, filePath, nodes); | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
...l-generator-core/src/main/java/io.ballerina.workermodelgenerator.core/ModelGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package io.ballerina.workermodelgenerator.core; | ||
|
||
import com.google.gson.Gson; | ||
import com.google.gson.JsonElement; | ||
import io.ballerina.compiler.api.SemanticModel; | ||
import io.ballerina.compiler.syntax.tree.ModulePartNode; | ||
import io.ballerina.compiler.syntax.tree.NonTerminalNode; | ||
import io.ballerina.compiler.syntax.tree.SyntaxKind; | ||
import io.ballerina.compiler.syntax.tree.SyntaxTree; | ||
import io.ballerina.projects.Document; | ||
import io.ballerina.tools.text.LineRange; | ||
import io.ballerina.tools.text.TextDocument; | ||
import io.ballerina.tools.text.TextRange; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
/** | ||
* Generator for the worker model. | ||
* | ||
* @since 2201.9.0 | ||
*/ | ||
public class ModelGenerator { | ||
|
||
private final SemanticModel semanticModel; | ||
private final Document document; | ||
private final LineRange lineRange; | ||
private static final List<SyntaxKind> validCanvasNodeKinds = Arrays.asList( | ||
SyntaxKind.FUNCTION_DEFINITION, | ||
SyntaxKind.RESOURCE_ACCESSOR_DEFINITION | ||
); | ||
|
||
public ModelGenerator(SemanticModel model, Document document, LineRange lineRange) { | ||
this.semanticModel = model; | ||
this.document = document; | ||
this.lineRange = lineRange; | ||
} | ||
|
||
/** | ||
* Generates a worker model for the given canvas node. | ||
* | ||
* @return JSON representation of the worker model | ||
* @throws Exception if the canvas is not valid | ||
*/ | ||
public JsonElement getWorkerModel() throws Exception { | ||
// Obtain the code block representing the canvas | ||
SyntaxTree syntaxTree = document.syntaxTree(); | ||
TextDocument textDocument = syntaxTree.textDocument(); | ||
ModulePartNode modulePartNode = syntaxTree.rootNode(); | ||
int start = textDocument.textPositionFrom(lineRange.startLine()); | ||
int end = textDocument.textPositionFrom(lineRange.endLine()); | ||
NonTerminalNode canvasNode = modulePartNode.findNode(TextRange.from(start, end - start), true); | ||
|
||
// Check if the canvas node is a valid type | ||
if (!validCanvasNodeKinds.contains(canvasNode.kind())) { | ||
throw new Exception(); | ||
} | ||
|
||
// Build the flow diagram | ||
FlowBuilder flowBuilder = new FlowBuilder("1", "flow1", "path", semanticModel); | ||
canvasNode.accept(flowBuilder); | ||
|
||
// Convert the flow diagram to a JSON object | ||
Gson gson = new Gson(); | ||
return gson.toJsonTree(flowBuilder.build()); | ||
} | ||
} |
158 changes: 158 additions & 0 deletions
158
...odel-generator-core/src/main/java/io.ballerina.workermodelgenerator.core/NodeBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package io.ballerina.workermodelgenerator.core; | ||
|
||
import io.ballerina.compiler.api.SemanticModel; | ||
import io.ballerina.compiler.api.symbols.Symbol; | ||
import io.ballerina.compiler.api.symbols.TypeDescKind; | ||
import io.ballerina.compiler.api.symbols.TypeSymbol; | ||
import io.ballerina.compiler.syntax.tree.AsyncSendActionNode; | ||
import io.ballerina.compiler.syntax.tree.CaptureBindingPatternNode; | ||
import io.ballerina.compiler.syntax.tree.CheckExpressionNode; | ||
import io.ballerina.compiler.syntax.tree.ExpressionNode; | ||
import io.ballerina.compiler.syntax.tree.ExpressionStatementNode; | ||
import io.ballerina.compiler.syntax.tree.Node; | ||
import io.ballerina.compiler.syntax.tree.NodeVisitor; | ||
import io.ballerina.compiler.syntax.tree.ReceiveActionNode; | ||
import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; | ||
import io.ballerina.compiler.syntax.tree.SyncSendActionNode; | ||
import io.ballerina.compiler.syntax.tree.SyntaxKind; | ||
import io.ballerina.compiler.syntax.tree.TypedBindingPatternNode; | ||
import io.ballerina.compiler.syntax.tree.VariableDeclarationNode; | ||
import io.ballerina.compiler.syntax.tree.WaitActionNode; | ||
import io.ballerina.tools.text.LinePosition; | ||
import io.ballerina.workermodelgenerator.core.model.CanvasPosition; | ||
import io.ballerina.workermodelgenerator.core.model.CodeLocation; | ||
import io.ballerina.workermodelgenerator.core.model.InputPort; | ||
import io.ballerina.workermodelgenerator.core.model.WorkerNodeJsonBuilder; | ||
import io.ballerina.workermodelgenerator.core.model.OutputPort; | ||
import io.ballerina.workermodelgenerator.core.model.WorkerNode; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
/** | ||
* Builder implementation for creating a {@link WorkerNode} instance. | ||
* | ||
* @since 2201.9.0 | ||
*/ | ||
class NodeBuilder extends NodeVisitor implements WorkerNodeJsonBuilder { | ||
|
||
private final SemanticModel semanticModel; | ||
|
||
// Json variables | ||
private String id; | ||
private TemplateKind templateKind; | ||
private CodeLocation codeLocation; | ||
private CanvasPosition canvasPosition; | ||
private final List<InputPort> inputPorts; | ||
private final List<OutputPort> outputPorts; | ||
|
||
// State variables | ||
private String toWorker; | ||
private String fromWorker; | ||
private TypeDescKind type; | ||
private String name; | ||
|
||
public NodeBuilder(SemanticModel semanticModel) { | ||
this.inputPorts = new ArrayList<>(); | ||
this.outputPorts = new ArrayList<>(); | ||
this.semanticModel = semanticModel; | ||
} | ||
|
||
@Override | ||
public void visit(ExpressionStatementNode expressionStatementNode) { | ||
ExpressionNode expression = expressionStatementNode.expression(); | ||
expression.accept(this); | ||
} | ||
|
||
@Override | ||
public void visit(CheckExpressionNode checkExpressionNode) { | ||
checkExpressionNode.expression().accept(this); | ||
} | ||
|
||
@Override | ||
public void visit(ReceiveActionNode receiveActionNode) { | ||
Node receiverWorker = receiveActionNode.receiveWorkers(); | ||
if (receiverWorker.kind() == SyntaxKind.SIMPLE_NAME_REFERENCE) { | ||
this.fromWorker = ((SimpleNameReferenceNode) receiverWorker).name().text(); | ||
} | ||
} | ||
|
||
@Override | ||
public void visit(AsyncSendActionNode asyncSendActionNode) { | ||
analyzeSendAction(asyncSendActionNode.peerWorker(), asyncSendActionNode.expression()); | ||
} | ||
|
||
@Override | ||
public void visit(SyncSendActionNode syncSendActionNode) { | ||
analyzeSendAction(syncSendActionNode.peerWorker(), syncSendActionNode.expression()); | ||
} | ||
|
||
private void analyzeSendAction(SimpleNameReferenceNode receiverNode, ExpressionNode expressionNode) { | ||
this.toWorker = receiverNode.name().text(); | ||
Optional<TypeSymbol> typeSymbol = this.semanticModel.typeOf(expressionNode); | ||
this.type = typeSymbol.isPresent() ? typeSymbol.get().typeKind() : TypeDescKind.NONE; | ||
this.addOutputPort("id", this.type, this.toWorker); | ||
} | ||
|
||
@Override | ||
public void visit(VariableDeclarationNode variableDeclarationNode) { | ||
// Find the name of the sender | ||
Optional<ExpressionNode> initializer = variableDeclarationNode.initializer(); | ||
if (initializer.isEmpty()) { | ||
return; | ||
} | ||
initializer.get().accept(this); | ||
|
||
// Find the parameter name | ||
TypedBindingPatternNode typedBindingPatternNode = variableDeclarationNode.typedBindingPattern(); | ||
typedBindingPatternNode.bindingPattern().accept(this); | ||
|
||
// Find the parameter type | ||
Optional<Symbol> symbol = this.semanticModel.symbol(typedBindingPatternNode.typeDescriptor()); | ||
this.type = (symbol.isPresent() && symbol.get() instanceof TypeSymbol typeSymbol) ? typeSymbol.typeKind() : | ||
TypeDescKind.NONE; | ||
|
||
this.addInputPort("id", this.type, this.name, this.fromWorker); | ||
} | ||
|
||
@Override | ||
public void visit(CaptureBindingPatternNode captureBindingPatternNode) { | ||
this.name = captureBindingPatternNode.variableName().text(); | ||
} | ||
|
||
@Override | ||
public void setId(String id) { | ||
this.id = id; | ||
} | ||
|
||
@Override | ||
public void setTemplateKind(TemplateKind templateKind) { | ||
this.templateKind = templateKind; | ||
} | ||
|
||
@Override | ||
public void addInputPort(String id, TypeDescKind type, String name, String sender) { | ||
this.inputPorts.add(new InputPort(id, type, name, sender)); | ||
} | ||
|
||
@Override | ||
public void addOutputPort(String id, TypeDescKind type, String receiver) { | ||
this.outputPorts.add(new OutputPort(id, type, receiver)); | ||
} | ||
|
||
@Override | ||
public void setCodeLocation(LinePosition start, LinePosition end) { | ||
this.codeLocation = new CodeLocation(start, end); | ||
} | ||
|
||
@Override | ||
public void setCanvasPosition(int x, int y) { | ||
this.canvasPosition = new CanvasPosition(x, y); | ||
} | ||
|
||
@Override | ||
public WorkerNode build() { | ||
return new WorkerNode(id, templateKind, codeLocation, canvasPosition, inputPorts, outputPorts); | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
...del-generator-core/src/main/java/io.ballerina.workermodelgenerator.core/TemplateKind.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package io.ballerina.workermodelgenerator.core; | ||
|
||
public enum TemplateKind { | ||
SWITCH, | ||
TRANSFORMER | ||
} |