package generators;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.AbstractMap.SimpleEntry;
import code.ast.Block;
import code.ast.CompilationUnit;
import code.ast.FieldDeclaration;
import code.ast.MethodDeclaration;
import code.ast.TypeDeclaration;
import code.ast.VariableDeclaration;
import models.Edge;
import models.Node;
import models.algebra.Constant;
import models.algebra.Expression;
import models.algebra.Field;
import models.algebra.InvalidMessage;
import models.algebra.ParameterizedIdentifierIsFutureWork;
import models.algebra.Position;
import models.algebra.Term;
import models.algebra.Type;
import models.algebra.UnificationFailed;
import models.algebra.ValueUndefined;
import models.algebra.Variable;
import models.dataConstraintModel.Channel;
import models.dataConstraintModel.ChannelMember;
import models.dataConstraintModel.DataConstraintModel;
import models.dataConstraintModel.JsonAccessor;
import models.dataConstraintModel.ResourceHierarchy;
import models.dataConstraintModel.ResourcePath;
import models.dataConstraintModel.Selector;
import models.dataFlowModel.DataFlowEdge;
import models.dataFlowModel.DataFlowGraph;
import models.dataFlowModel.DataTransferChannel;
import models.dataFlowModel.DataTransferModel;
import models.dataFlowModel.PushPullAttribute;
import models.dataFlowModel.PushPullValue;
import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork;
import models.dataFlowModel.ResourceNode;
import models.dataFlowModel.ChannelNode;
import models.dataFlowModel.StoreAttribute;
import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor;
public class CodeGeneratorFromDataFlowGraph extends CodeGenerator {
public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList<ResourceNode> components, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph,
TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList<CompilationUnit> codes, ILanguageSpecific langSpec) {
Map<ResourceHierarchy, TypeDeclaration> resourceComponents = new HashMap<>();
Map<ResourceHierarchy, MethodDeclaration> resourceConstructors = new HashMap<>();
List<Map.Entry<ResourceHierarchy, VariableDeclaration>> constructorParams = new ArrayList<>();
List<Map.Entry<ResourceHierarchy, String>> constructorStatements = new ArrayList<>();
Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>> updateStatements = new HashMap<>();
// For each components (1st pass).
for (Node componentNode: components) {
ResourceNode resourceNode = (ResourceNode) componentNode;
TypeDeclaration component = null;
if (generatesComponent(resourceNode.getResourceHierarchy())) {
// A component will be generated for this resource.
String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec);
component = resourceComponents.get(resourceNode.getResourceHierarchy());
List<ResourceHierarchy> depends = new ArrayList<>();
if (component == null) {
// Add compilation unit for this component.
component = langSpec.newTypeDeclaration(resourceName);
resourceComponents.put(resourceNode.getResourceHierarchy(), component);
CompilationUnit cu = langSpec.newCompilationUnit(component);
codes.add(cu);
// Declare the constructor and the fields to refer to other resources.
MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, dependedRootComponentGraph, depends, langSpec);
if (resourceNode.getResourceHierarchy().getParent() == null) {
// For each root resource
// Update the main component for this component.
updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec);
}
// Declare the fields to refer to reference resources.
declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec);
if (constructor.getParameters() == null) {
component.removeMethod(constructor);
} else {
resourceConstructors.put(resourceNode.getResourceHierarchy(), constructor);
}
}
}
}
// For each components (2nd pass).
for (Node componentNode: components) {
// Declare this resource.
ResourceNode resourceNode = (ResourceNode) componentNode;
Type resStateType = getImplStateType(resourceNode.getResourceHierarchy(), langSpec);
TypeDeclaration component = null;
TypeDeclaration parentComponent = null;
if (generatesComponent(resourceNode.getResourceHierarchy())) {
String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec);
component = resourceComponents.get(resourceNode.getResourceHierarchy());
// Declare the field in this resource to store the state.
if (((StoreAttribute) resourceNode.getAttribute()).isStored()) {
declareStateField(resourceNode, resourceName, component, resStateType, constructorParams, langSpec);
}
// Declare the getter methods in this resource to obtain the children resources.
declareChildGetterMethod(resourceNode, component, langSpec);
}
if (resourceNode.getResourceHierarchy().getParent() != null) {
parentComponent = resourceComponents.get(resourceNode.getResourceHierarchy().getParent());
}
// Declare cache fields and update methods in this resource.
Map.Entry<List<String>, Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>>> initStatementsAndUpdateUpdates = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, langSpec);
if (component == null) {
// Constructor statements were not added to any component because no component had been generated.
for (String statement: initStatementsAndUpdateUpdates.getKey()) {
constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement));
}
}
for (Map.Entry<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>> entry: initStatementsAndUpdateUpdates.getValue().entrySet()) {
updateStatements.put(entry.getKey(), entry.getValue());
}
// Declare the state field and reference fields in the parent component.
if (component == null) {
declareFieldsInParentComponent(resourceNode, parentComponent, constructorParams, langSpec);
}
// Declare the getter method in this resource to obtain the state.
MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, parentComponent, resStateType, langSpec);
// Declare the accessor method in the main component to call the getter method.
declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, langSpec);
// Declare input methods in this component and the main component.
Map.Entry<List<String>, Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>>> initStatementsAndInputUpdates = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, model, langSpec);
if (component == null) {
// Constructor statements were not added to any component because no component had been generated.
for (String statement: initStatementsAndInputUpdates.getKey()) {
constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement));
}
}
for (Map.Entry<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>> entry: initStatementsAndInputUpdates.getValue().entrySet()) {
updateStatements.put(entry.getKey(), entry.getValue());
}
}
// Add constructor parameters to the ancestor components.
for (ResourceNode root: flowGraph.getRootResourceNodes()) {
addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams, langSpec);
}
// Add constructor statements.
for (Map.Entry<ResourceHierarchy, String> entry: constructorStatements) {
resourceConstructors.get(entry.getKey()).addStatement(entry.getValue());
}
// Add update statements.
for (MethodDeclaration method: updateStatements.keySet()) {
Expression updateExp = updateStatements.get(method).getKey();
ResourceHierarchy childRes = updateStatements.get(method).getValue();
TypeDeclaration childComponent = resourceComponents.get(childRes);
addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, childRes, childComponent, langSpec);
}
}
private static List<VariableDeclaration> addConstructorParameters(ResourceHierarchy resource, Map<ResourceHierarchy, TypeDeclaration> resourceComponents,
Map<ResourceHierarchy, MethodDeclaration> resourceConstructors, List<Entry<ResourceHierarchy, VariableDeclaration>> constructorParams, ILanguageSpecific langSpec) {
List<VariableDeclaration> params = new ArrayList<>();
for (ResourceHierarchy child: resource.getChildren()) {
params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams, langSpec));
}
for (Entry<ResourceHierarchy, VariableDeclaration> paramEnt: constructorParams) {
if (paramEnt.getKey().equals(resource)) {
params.add(paramEnt.getValue());
}
}
if (params.size() > 0) {
MethodDeclaration constructor = resourceConstructors.get(resource);
if (constructor == null) {
if (resourceComponents.get(resource) != null) {
String resourceName = getComponentName(resource, langSpec);
constructor = new MethodDeclaration(resourceName, true);
Block body = new Block();
constructor.setBody(body);
resourceComponents.get(resource).addMethod(constructor);
resourceConstructors.put(resource, constructor);
}
}
if (constructor != null) {
for (VariableDeclaration param: params) {
constructor.addParameter(param);
constructor.getBody().addStatement(langSpec.getFieldAccessor(langSpec.toVariableName(param.getName())) + langSpec.getAssignment() + langSpec.toVariableName(param.getName()) + langSpec.getStatementDelimiter());
}
}
}
if (resource.getNumParameters() > 0) params.clear();
return params;
}
private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy childRes, TypeDeclaration childComponent, ILanguageSpecific langSpec) {
Type replacedJsonType = childRes.getResourceStateType();
String replacingClassName = getComponentName(childRes, langSpec);
Map<Position, Term> subTerms = ((Term) exp).getSubTerms(Term.class);
for (Entry<Position, Term> termEnt: subTerms.entrySet()) {
Term jsonTerm = termEnt.getValue();
if (jsonTerm.getType().equals(replacedJsonType)) {
MethodDeclaration childConstructor = getConstructor(childComponent);
List<String> params = new ArrayList<>();
for (VariableDeclaration var: childConstructor.getParameters()) {
JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot);
jsonMember.addChild(jsonTerm);
jsonMember.addChild(new Constant("\"" + var.getName() + "\""));
Expression param = jsonMember.reduce();
if (param != null) {
params.add(param.toImplementation(new String[] {""}));
} else {
params.add(var.getName());
}
}
((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params)));
}
}
String[] sideEffects = new String[] {""};
String newState = exp.toImplementation(sideEffects);
String updateStatement;
if (exp instanceof Term && ((Term) exp).getSymbol().isImplWithSideEffect()) {
updateStatement = sideEffects[0];
} else {
updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter();
}
method.addFirstStatement(updateStatement);
}
private MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph,
List<ResourceHierarchy> depends, ILanguageSpecific langSpec) {
// Declare a constructor in each component.
MethodDeclaration constructor = component.createConstructor();
Block block = new Block();
constructor.setBody(block);
// Declare fields in each component. (for data-flow graph)
for (Edge resToCh: resourceNode.getOutEdges()) {
DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel();
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
// Check if the output resource is outside of the channel scope.
boolean outsideOutputResource = false;
for (ChannelMember cm: ch.getOutputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) {
outsideOutputResource = true; // Regarded as push transfer.
break;
}
}
if (((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) {
for (Edge chToRes: resToCh.getDestination().getOutEdges()) {
// for PUSH transfer
if (chToRes.getDestination() instanceof ResourceNode) {
ResourceHierarchy dstRes = addReference(component, constructor, ((ResourceNode) chToRes.getDestination()).getOutSideResource().getResourceHierarchy(), langSpec);
if (outsideOutputResource) {
if (dstRes != null && dstRes.getParent() != null) {
// Reference to root resource.
addReference(component, constructor, dstRes.getRoot(), langSpec);
}
}
if (!depends.contains(dstRes)) depends.add(dstRes);
}
}
}
}
for (Edge chToRes: resourceNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
ResourceHierarchy srcRes = ((ResourceNode) resToCh.getSource()).getOutSideResource().getResourceHierarchy();
DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel();
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(srcRes) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
// Check if the output resource is outside of the channel scope.
boolean outsideOutputResource = false;
for (ChannelMember cm: ch.getOutputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) {
outsideOutputResource = true; // Regarded as push transfer.
break;
}
}
if ((((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) {
// for PULL transfer
srcRes = addReference(component, constructor, ((ResourceNode) resToCh.getSource()).getOutSideResource().getResourceHierarchy(), langSpec);
if (outsideInputResource) {
if (srcRes != null & srcRes.getParent() != null) {
// Reference to root resource.
addReference(component, constructor, srcRes.getRoot(), langSpec);
}
}
if (!depends.contains(srcRes)) depends.add(srcRes);
}
}
}
// Declare a field to refer to outside resources.
if (resourceNode.getParent() == null) {
for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) {
for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) {
if (resourceNode.getResourceHierarchy().equals(dependingRes)) {
// Declare a field to refer to outside resources.
depends.add(dependedRes);
addReference(component, constructor, dependedRes, langSpec);
}
}
}
}
return constructor;
}
private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType, List<Map.Entry<ResourceHierarchy, VariableDeclaration>> constructorParams, ILanguageSpecific langSpec) {
Set<ResourceHierarchy> children = resourceNode.getResourceHierarchy().getChildren();
if (children == null || children.size() == 0) {
// leaf resource.
FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue()));
component.addField(stateField);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), langSpec.newVariableDeclaration(resStateType, langSpec.toVariableName(resourceName))));
} else {
ResourceHierarchy child = children.iterator().next();
if (children.size() == 1 && child.getNumParameters() > 0) {
// map or list.
FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue()));
component.addField(stateField);
} else {
// class
for (ResourceHierarchy c: children) {
String childTypeName = getComponentName(c, langSpec);
Type childType = null;
if (generatesComponent(c)) {
// The child has a component.
childType = new Type(childTypeName, childTypeName);
String fieldName = langSpec.toVariableName(childTypeName);
FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue()));
component.addField(stateField);
}
}
}
}
}
private void declareFieldsInParentComponent(ResourceNode resourceNode, TypeDeclaration parentComponent, List<Map.Entry<ResourceHierarchy, VariableDeclaration>> constructorParams, ILanguageSpecific langSpec) {
// Declare reference fields for push/pull data transfer.
boolean noPullTransfer = true;
for (Edge resToCh : resourceNode.getOutEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel();
for (Edge chToRes: re.getDestination().getOutEdges()) {
ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource();
// Check if the destination resource is outside of the channel scope.
boolean outsideOutputResource = false;
for (ChannelMember cm: ch.getOutputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(dstRes.getResourceHierarchy()) && cm.isOutside()) {
outsideOutputResource = true; // Regarded as push transfer.
break;
}
}
if (outsideOutputResource) {
// Declare a field in the parent component to refer to the destination resource of push transfer.
String dstResName = null;
if (!generatesComponent(dstRes.getResourceHierarchy())) {
dstRes = dstRes.getParent();
}
dstResName = getComponentName(dstRes.getResourceHierarchy(), langSpec);
FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName));
parentComponent.addField(refFieldForPush);
if (dstRes.getParent() != null) {
// Reference to root resource.
String dstRootResName = getComponentName(dstRes.getRoot().getResourceHierarchy(), langSpec);
Type dstRootResType = new Type(dstRootResName, dstRootResName);
dstRootResName = langSpec.toVariableName(dstRootResName);
FieldDeclaration refRootFieldForPush = langSpec.newFieldDeclaration(dstRootResType, dstRootResName);
parentComponent.addField(refRootFieldForPush);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(dstRootResType, dstRootResName)));
}
}
}
}
for (Edge chToRes : resourceNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource();
DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel();
// Check if the source resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
if (outsideInputResource) {
// Declare a field in the parent component to refer to the source resource of pull transfer.
String srcResName = null;
if (!generatesComponent(srcRes.getResourceHierarchy())) {
srcRes = srcRes.getParent();
}
srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec);
FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName));
parentComponent.addField(refFieldForPull);
if (srcRes.getParent() != null) {
// Reference to root resource.
String srcRootResName = getComponentName(srcRes.getRoot().getResourceHierarchy(), langSpec);
Type srcRootResType = new Type(srcRootResName, srcRootResName);
srcRootResName = langSpec.toVariableName(srcRootResName);
FieldDeclaration refRootFieldForPull = langSpec.newFieldDeclaration(srcRootResType, srcRootResName);
parentComponent.addField(refRootFieldForPull);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(srcRootResType, srcRootResName)));
}
noPullTransfer = false;
}
}
}
// Declare the state field in the parent component.
ResourceHierarchy res = resourceNode.getOutSideResource().getResourceHierarchy();
if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) {
String resName = getComponentName(res, langSpec);
FieldDeclaration stateField = langSpec.newFieldDeclaration(res.getResourceStateType(), langSpec.toVariableName(resName));
parentComponent.addField(stateField);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(res.getResourceStateType(), langSpec.toVariableName(resName))));
}
}
private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, Type resStateType, ILanguageSpecific langSpec) {
// Declare the getter method of the resource state.
MethodDeclaration stateGetter = null;
if (component != null) {
// A component is created for this resource.
stateGetter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType);
component.addMethod(stateGetter);
} else {
// No component is created for this resource.
List<VariableDeclaration> getterParams = new ArrayList<>();
int v = 1;
for (Selector param: resourceNode.getSelectors()) {
if (param.getExpression() instanceof Variable) {
Variable var = (Variable) param.getExpression();
getterParams.add(new VariableDeclaration(var.getType(), var.getName()));
} else if (param.getExpression() instanceof Term) {
Term var = (Term) param.getExpression();
getterParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
String resCompName = getComponentName(resourceNode.getResourceHierarchy(), langSpec);
if (getterParams.size() == 0) {
stateGetter = new MethodDeclaration(getterPrefix + resCompName, resStateType);
} else {
stateGetter = new MethodDeclaration(getterPrefix + resCompName, false, resStateType, getterParams);
}
if (parentComponent != null) {
parentComponent.addMethod(stateGetter);
}
}
if (((StoreAttribute) resourceNode.getAttribute()).isStored()) {
if (component != null) {
// A component is created for this resource.
fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, langSpec);
} else {
// No component is created for this resource.
fillChildGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resourceNode.getResourceHierarchy().getParent().getResourceStateType(), langSpec);
}
} else {
// invocations to other getter methods when at least one incoming data-flow edges is PULL-style.
boolean isContainedPush = false;
DataTransferChannel ch = null;
HashMap<ChannelMember, IResourceStateAccessor> inputResourceToStateAccessor = new HashMap<>();
for (Edge chToRes: resourceNode.getInEdges()) {
DataTransferChannel ch2 = ((ChannelNode) chToRes.getSource()).getChannel();
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataFlowEdge dIn = (DataFlowEdge) resToCh;
ChannelMember in = null;
for (ChannelMember cm: ch2.getInputChannelMembers()) {
if (cm.getResource().equals(((ResourceNode) dIn.getSource()).getOutSideResource())) {
in = cm;
break;
}
}
if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) {
// PUSH transfer
isContainedPush = true;
inputResourceToStateAccessor.put(in, getPushAccessor());
} else {
// PULL transfer
inputResourceToStateAccessor.put(in, getPullAccessor());
ch = ((ChannelNode) resToCh.getDestination()).getChannel(); // pull containing input side channel is always one.
}
}
}
// for reference channel members.
for (ChannelMember c: ch.getReferenceChannelMembers()) {
inputResourceToStateAccessor.put(c, getPullAccessor()); // by pull data transfer
}
// generate a return statement.
try {
for (ChannelMember out: ch.getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(out.getResource())) {
String[] sideEffects = new String[] {""};
if (!isContainedPush) {
// All incoming edges are in PULL-style.
String curState = ch.deriveUpdateExpressionOf(out, getPullAccessor()).toImplementation(sideEffects);
stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter());
} else {
// At least one incoming edge is in PUSH-style.
String curState = ch.deriveUpdateExpressionOf(out, getPullAccessor(), inputResourceToStateAccessor).toImplementation(sideEffects);
stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter());
}
break;
}
}
} catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork
| InvalidMessage | UnificationFailed | ValueUndefined e) {
e.printStackTrace();
}
}
return stateGetter;
}
private void declareChildGetterMethod(ResourceNode resourceNode, TypeDeclaration component, ILanguageSpecific langSpec) {
// Declare the getter methods in this resource to obtain the children resources.
for (ResourceNode child: resourceNode.getChildren()) {
if (generatesComponent(child.getResourceHierarchy())) {
// A component for the child is generated.
List<VariableDeclaration> params = new ArrayList<>();
int v = 1;
for (Selector param: child.getSelectors()) {
if (param.getExpression() instanceof Variable) {
Variable var = (Variable) param.getExpression();
params.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
} else if (param.getExpression() instanceof Term) {
Term var = (Term) param.getExpression();
params.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
}
v++;
}
String childCompName = getComponentName(child.getResourceHierarchy(), langSpec);
Type childType = new Type(childCompName, childCompName);
MethodDeclaration childGetter = null;
if (params.size() == 0) {
childGetter = langSpec.newMethodDeclaration(getterPrefix + childCompName, childType);
} else {
childGetter = langSpec.newMethodDeclaration(getterPrefix + childCompName, false, childType, params);
}
fillChildGetterMethod(childGetter, child.getResourceHierarchy(), resourceNode.getResourceStateType(), langSpec);
component.addMethod(childGetter);
}
}
}
private Map.Entry<List<String>, Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, ILanguageSpecific langSpec) {
// Declare cash fields and update methods in the component.
String resComponentName = langSpec.toComponentName(resourceNode.getResourceName());
List<String> constructorStatements = new ArrayList<>();
Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>> updateStatements = new HashMap<>();
for (Edge chToRes: resourceNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel();
DataFlowEdge re = (DataFlowEdge) resToCh;
ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource();
String srcResName = srcRes.getResourceName();
String srcResComponentName = langSpec.toComponentName(srcResName);
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) {
// for push data transfer
// Declare an update method in the type of the destination resource.
ArrayList<VariableDeclaration> vars = new ArrayList<>();
vars.add(langSpec.newVariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName()));
// For the refs.
for (ResourcePath ref: ch.getReferenceResources()) {
if (!resourceNode.getInSideResources().contains(ref)) {
vars.add(langSpec.newVariableDeclaration(ref.getResourceStateType(), ref.getResourceName()));
}
}
MethodDeclaration update = langSpec.newMethodDeclaration(updateMethodName + srcResComponentName, false, null, vars);
if (component != null) {
component.addMethod(update);
} else if (parentComponent != null) {
parentComponent.addMethod(update);
}
// Add a statement to update the state field
if (((StoreAttribute) resourceNode.getAttribute()).isStored()) {
try {
for (ChannelMember out: ch.getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(out.getResource())) {
Expression updateExp = ch.deriveUpdateExpressionOf(out, getPushAccessor());
// Replace Json constructor with a constructor of the child resource.
ResourceHierarchy outRes = out.getResource().getResourceHierarchy();
if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) {
ResourceHierarchy childRes = outRes.getChildren().iterator().next();
Type childStateType = childRes.getResourceStateType();
if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) {
updateStatements.put(update, new AbstractMap.SimpleEntry<>(updateExp, childRes));
break;
}
}
// Add statements to the input method.
String[] sideEffects = new String[] {""};
String curState = updateExp.toImplementation(sideEffects);
String updateStatement;
if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) {
updateStatement = sideEffects[0];
} else {
updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + curState + langSpec.getStatementDelimiter(); // this.value = ...
}
if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) {
update.addFirstStatement(updateStatement);
}
break;
}
}
} catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork
| InvalidMessage | UnificationFailed | ValueUndefined e1) {
e1.printStackTrace();
}
}
// Declare the field to cache the state of the source resource in the type of the destination resource.
if (resToCh.getDestination().getIndegree() > 1) {
// If incoming edges are multiple
if (langSpec.declareField()) {
// Declare the cache field.
FieldDeclaration cacheField = langSpec.newFieldDeclaration(
srcRes.getResourceStateType(),
srcRes.getResourceName(),
langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getResourceHierarchy().getInitialValue()));
if (component != null) {
component.addField(cacheField);
} else if (parentComponent != null){
parentComponent.addField(cacheField);
}
}
// Update the cache field.
String cashStatement = langSpec.getFieldAccessor(langSpec.toVariableName(srcResName)) + langSpec.getAssignment() + langSpec.toVariableName(srcResName) + langSpec.getStatementDelimiter();
if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) {
update.addFirstStatement(cashStatement);
}
}
Set<ChannelMember> outsideInputMembers = new HashSet<>();
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.isOutside()) {
outsideInputMembers.add(cm);
}
}
if (outsideInputMembers.size() > 0) {
Map<ChannelMember, Entry<ResourcePath, Set<ChannelMember>>> resourcePaths = null;
for (ChannelMember out: ch.getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(out.getResource())) {
try {
resourcePaths = ch.fillOutsideResourcePaths(out, getPullAccessor());
} catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork
| InvalidMessage | UnificationFailed | ValueUndefined e) {
e.printStackTrace();
}
break;
}
}
if (resourcePaths != null && resourcePaths.size() > 0) {
for (ChannelMember outsideMember: outsideInputMembers) {
for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) {
if (dependingMember.getResource().equals(srcRes)) {
// An outside input resource path depends on srcRes.
ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey();
String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec));
Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null);
if (generatesComponent(outsidePath.getResourceHierarchy())) {
outsideExp = ((Term) outsideExp).getChild(0);
}
Expression nextExp = dependingMember.getStateTransition().getNextStateExpression();
if (nextExp != null && outsideExp instanceof Term) {
if (nextExp instanceof Variable) {
outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec))));
} else {
// ToDo.
}
}
String[] sideEffects = new String[] {""};
String outsideAccessor = outsideExp.toImplementation(sideEffects);
String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter();
update.addStatement(updateReference); // Update the reference field.
// Update constructor.
if (component != null) {
MethodDeclaration constructor = getConstructor(component);
constructor.addStatement(updateReference); // Initialize the reference field.
} else if (parentComponent != null){
constructorStatements.add(updateReference);
}
}
}
}
}
}
// Add an invocation to another update method (for a chain of update method invocations).
for (Edge resToCh2: resourceNode.getOutEdges()) {
DataFlowEdge dOut = (DataFlowEdge) resToCh2;
DataTransferChannel ch2 = ((ChannelNode) resToCh2.getDestination()).getChannel();
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource2 = false;
Set<ChannelMember> outsideInputMembers2 = new HashSet<>();
for (ChannelMember cm: ch2.getInputChannelMembers()) {
if (cm.isOutside()) {
outsideInputMembers2.add(cm);
if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy())) {
outsideInputResource2 = true; // Regarded as pull transfer.
}
}
}
if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) {
for (Edge chToRes2: resToCh2.getDestination().getOutEdges()) {
// PUSH transfer
ChannelMember in = null;
for (ChannelMember cm: ch2.getInputChannelMembers()) {
if (cm.getResource().equals(resourceNode.getOutSideResource())) {
in = cm;
break;
}
}
Map<MethodDeclaration, Set<ResourcePath>> referredResources = new HashMap<>();
List<String> params = new ArrayList<>();
params.add(langSpec.getFieldAccessor(fieldOfResourceState));
Set<ResourcePath> referredSet = referredResources.get(update);
for (ChannelMember rc: ch2.getReferenceChannelMembers()) {
// to get the value of reference member.
ResourcePath ref = rc.getResource();
if (referredSet == null) {
referredSet = new HashSet<>();
referredResources.put(update, referredSet);
}
if (!resourceNode.getInSideResources().contains(ref)) {
String refVarName = ref.getResourceName();
if (!referredSet.contains(ref)) {
referredSet.add(ref);
Expression refGetter = getPullAccessor().getCurrentStateAccessorFor(rc, in);
String[] sideEffects = new String[] {""};
String refExp = refGetter.toImplementation(sideEffects);
String refTypeName = ref.getResourceStateType().getInterfaceTypeName();
update.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter());
}
params.add(refVarName);
}
}
update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) chToRes2.getDestination()).getResourceName()),
updateMethodName + resComponentName,
params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams);
}
}
if (outsideInputMembers2.size() > 0) {
if (!generatesComponent(resourceNode.getResourceHierarchy())) {
// srcRes2 does not have a component.
ResourcePath srcRes2 = resourceNode.getOutSideResource();
for (ChannelMember out: ch2.getOutputChannelMembers()) {
if (!generatesComponent(out.getResource().getResourceHierarchy())) {
// Also dstRes2 does not have a component.
ResourcePath dstRes2 = out.getResource();
if (srcRes2.getParent().equals(dstRes2.getParent())) {
Map<ChannelMember, Entry<ResourcePath, Set<ChannelMember>>> resourcePaths = null;
try {
resourcePaths = ch2.fillOutsideResourcePaths(out, getPullAccessor());
if (resourcePaths != null && resourcePaths.size() > 0) {
for (ChannelMember outsideMember: outsideInputMembers2) {
for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) {
if (dependingMember.getResource().equals(srcRes2)) {
// An outside input resource path depends on srcRes.
ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey();
if (!generatesComponent(outsidePath.getResourceHierarchy())) {
outsidePath = outsidePath.getParent();
}
String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec));
Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null);
if (generatesComponent(outsidePath.getResourceHierarchy())) {
outsideExp = ((Term) outsideExp).getChild(0);
}
Expression nextExp = dependingMember.getStateTransition().getNextStateExpression();
if (nextExp != null && outsideExp instanceof Term) {
if (nextExp instanceof Variable) {
outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec))));
} else {
// ToDo.
}
}
String[] sideEffects = new String[] {""};
String outsideAccessor = outsideExp.toImplementation(sideEffects);
String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter();
update.addStatement(updateReference); // Update the reference field.
// Update constructor.
if (component != null) {
MethodDeclaration constructor = getConstructor(component);
constructor.addStatement(updateReference); // Initialize the reference field.
} else if (parentComponent != null) {
constructorStatements.add(updateReference);
}
}
}
}
}
} catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork
| InvalidMessage | UnificationFailed | ValueUndefined e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
}
}
return new AbstractMap.SimpleEntry<>(constructorStatements, updateStatements);
}
private Map.Entry<List<String>, Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component,
TypeDeclaration parentComponent, TypeDeclaration mainComponent, DataTransferModel model, ILanguageSpecific langSpec) {
// Declare input methods.
String resName = resourceNode.getResourceName();
String resComponentName = langSpec.toComponentName(resName);
List<String> constructorStatements = new ArrayList<>();
Map<MethodDeclaration, Map.Entry<Expression, ResourceHierarchy>> inputStatements = new HashMap<>();
for (Channel ch : model.getIOChannels()) {
for (ChannelMember out : ((DataTransferChannel) ch).getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(out.getResource())) {
Expression message = out.getStateTransition().getMessageExpression();
MethodDeclaration input = null;
MethodDeclaration inputAccessor = null;
if (message instanceof Term) {
// Declare an input method in this component.
ArrayList<VariableDeclaration> resInputParams = new ArrayList<>();
ArrayList<VariableDeclaration> mainInputParams = new ArrayList<>();
int v = 1;
for (Selector selector: resourceNode.getSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable var = (Variable) selector.getExpression();
resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
} else if (selector.getExpression() instanceof Term) {
Term var = (Term) selector.getExpression();
resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
}
v++;
}
if (resourceNode.getParent() != null) {
for (Selector selector: resourceNode.getParent().getAllSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable var = (Variable) selector.getExpression();
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
} else if (selector.getExpression() instanceof Term) {
Term var = (Term) selector.getExpression();
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
}
v++;
}
}
for (Variable var: message.getVariables().values()) {
resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
}
input = langSpec.newMethodDeclaration(((Term) message).getSymbol().getImplName(), false, null, resInputParams);
if (component != null) {
// A component is created for this resource.
component.addMethod(input);
} else if (parentComponent != null) {
// No component is created for this resource.
parentComponent.addMethod(input);
}
// Declare the accessor in the main component to call the input method.
String str = ((Term) message).getSymbol().getImplName();
inputAccessor = getMethod(mainComponent, str);
if (inputAccessor == null) {
inputAccessor = langSpec.newMethodDeclaration(str, false, null, mainInputParams);
mainComponent.addMethod(inputAccessor);
} else {
// Add type to a parameter without type.
if (inputAccessor.getParameters() != null) {
for (VariableDeclaration param: inputAccessor.getParameters()) {
if (param.getType() == null) {
for (VariableDeclaration p: mainInputParams) {
if (param.getName().equals(p.getName()) && p.getType() != null) {
param.setType(p.getType());
}
}
}
}
}
}
} else if (message instanceof Variable) {
// Declare an input method in this component.
ArrayList<VariableDeclaration> resInputParams = new ArrayList<>();
ArrayList<VariableDeclaration> mainInputParams = new ArrayList<>();
int v = 1;
for (Selector selector: resourceNode.getSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable var = (Variable) selector.getExpression();
resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
} else if (selector.getExpression() instanceof Term) {
Term var = (Term) selector.getExpression();
resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
}
v++;
}
if (resourceNode.getResourceHierarchy().getParent() != null) {
for (Selector selector: resourceNode.getParent().getSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable var = (Variable) selector.getExpression();
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName()));
} else if (selector.getExpression() instanceof Term) {
Term var = (Term) selector.getExpression();
mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v));
}
v++;
}
}
if (resInputParams.size() == 0) {
input = langSpec.newMethodDeclaration(((Variable) message).getName(), null);
} else {
input = langSpec.newMethodDeclaration(((Variable) message).getName(), false, null, resInputParams);
}
if (component != null) {
// A component is created for this resource.
component.addMethod(input);
} else if (parentComponent != null) {
// No component is created for this resource.
parentComponent.addMethod(input);
}
// Declare the accessor in the main component to call the input method.
String str = ((Variable) message).getName();
inputAccessor = getMethod(mainComponent, str);
if (inputAccessor == null) {
if (mainInputParams.size() == 0) {
inputAccessor = langSpec.newMethodDeclaration(str, null);
} else {
inputAccessor = langSpec.newMethodDeclaration(str, false, null, mainInputParams);
}
mainComponent.addMethod(inputAccessor);
}
}
// Add an invocation to the accessor method.
if (inputAccessor != null) {
Expression resExp = getPullAccessor().getDirectStateAccessorFor(out.getResource(), null);
List<String> args = new ArrayList<>();
if (resExp instanceof Term) {
// to access the parent
if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) {
args.add(((Variable)((Term) resExp).getChild(1)).getName());
}
resExp = ((Term) resExp).getChild(0);
}
String resourceAccess = resExp.toImplementation(new String[] {null});
if (message instanceof Term) {
for (Variable var: message.getVariables().values()) {
args.add(var.getName());
}
}
inputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter());
}
if (input != null) {
// Add a statement to update the state field to the input method.
try {
Expression updateExp = ((DataTransferChannel) ch).deriveUpdateExpressionOf(out, getPullAccessor());
// Replace Json constructor with a constructor of the child resource.
ResourceHierarchy outRes = out.getResource().getResourceHierarchy();
if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) {
ResourceHierarchy childRes = outRes.getChildren().iterator().next();
Type childStateType = childRes.getResourceStateType();
if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) {
inputStatements.put(input, new AbstractMap.SimpleEntry<>(updateExp, childRes));
updateExp = null;
}
}
// Add statements to the input method.
if (updateExp != null) {
String[] sideEffects = new String[] {""};
String newState = updateExp.toImplementation(sideEffects);
ResourceHierarchy resource = resourceNode.getResourceHierarchy();
if (generatesComponent(resource)) {
String updateStatement;
if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) {
updateStatement = sideEffects[0];
} else {
updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter();
}
input.addFirstStatement(updateStatement);
} else {
String updateStatement = null;
if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) {
// ToDo.
updateStatement = sideEffects[0];
} else {
if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) {
Term selector = new Term(DataConstraintModel.set);
selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState)));
selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName()));
selector.addChild(new Constant(newState));
String[] sideEffects2 = new String[] {""};
String newList = selector.toImplementation(sideEffects2);
updateStatement = sideEffects[0] + sideEffects2[0];
} else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) {
Term selector = new Term(DataConstraintModel.insert);
selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState)));
selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName()));
selector.addChild(new Constant(newState));
String[] sideEffects2 = new String[] {""};
String newMap = selector.toImplementation(sideEffects2);
updateStatement = sideEffects[0] + sideEffects2[0];
} else {
String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec));
updateStatement = sideEffects[0] + langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter();
}
if (updateStatement != null) {
input.addFirstStatement(updateStatement);
}
}
}
}
} catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork
| InvalidMessage | UnificationFailed | ValueUndefined e) {
e.printStackTrace();
}
// Add an invocation to an update method (for a chain of update method invocations).
for (Edge resToCh: resourceNode.getOutEdges()) {
DataFlowEdge dOut = (DataFlowEdge) resToCh;
DataTransferChannel ch2 = ((ChannelNode) resToCh.getDestination()).getChannel();
boolean outsideInputResource2 = false;
Set<ChannelMember> outsideInputMembers2 = new HashSet<>();
for (ChannelMember cm: ch2.getInputChannelMembers()) {
if (cm.isOutside()) {
outsideInputMembers2.add(cm);
if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy())) {
outsideInputResource2 = true; // Regarded as pull transfer.
}
}
}
if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) {
for (Edge chToRes: resToCh.getDestination().getOutEdges()) {
// PUSH transfer
ChannelMember in = null;
for (ChannelMember cm: ch2.getInputChannelMembers()) {
if (cm.getResource().equals(resourceNode.getOutSideResource())) {
in = cm;
break;
}
}
Map<MethodDeclaration, Set<ResourcePath>> referredResources = new HashMap<>();
List<String> params = new ArrayList<>();
params.add(langSpec.getFieldAccessor(fieldOfResourceState));
Set<ResourcePath> referredSet = referredResources.get(input);
for (ChannelMember rc: ch2.getReferenceChannelMembers()) {
// to get the value of reference member.
ResourcePath ref = rc.getResource();
if (referredSet == null) {
referredSet = new HashSet<>();
referredResources.put(input, referredSet);
}
if (!ref.equals(resourceNode.getOutSideResource())) {
String refVarName = ref.getResourceName();
if (!referredSet.contains(ref)) {
referredSet.add(ref);
Expression refGetter = getPullAccessor().getCurrentStateAccessorFor(rc, in);
String[] sideEffects = new String[] {""};
String refExp = refGetter.toImplementation(sideEffects);
String refTypeName = ref.getResourceStateType().getInterfaceTypeName();
input.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter());
}
params.add(refVarName);
}
}
input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) chToRes.getDestination()).getResourceName()),
updateMethodName + resComponentName,
params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams);
}
}
if (outsideInputMembers2.size() > 0) {
if (!generatesComponent(resourceNode.getResourceHierarchy())) {
ResourcePath srcRes2 = resourceNode.getOutSideResource();
for (ChannelMember out2: ch2.getOutputChannelMembers()) {
if (!generatesComponent(out2.getResource().getResourceHierarchy())) {
ResourcePath dstRes2 = out2.getResource();
if (srcRes2.getParent().equals(dstRes2.getParent())) {
Map<ChannelMember, Entry<ResourcePath, Set<ChannelMember>>> resourcePaths = null;
try {
resourcePaths = ch2.fillOutsideResourcePaths(out2, getPullAccessor());
if (resourcePaths != null && resourcePaths.size() > 0) {
for (ChannelMember outsideMember: outsideInputMembers2) {
for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) {
if (dependingMember.getResource().equals(srcRes2)) {
// An outside input resource path depends on srcRes.
ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey();
if (!generatesComponent(outsidePath.getResourceHierarchy())) {
outsidePath = outsidePath.getParent();
}
String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec));
Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null);
if (generatesComponent(outsidePath.getResourceHierarchy())) {
outsideExp = ((Term) outsideExp).getChild(0);
}
Expression nextExp = dependingMember.getStateTransition().getNextStateExpression();
if (nextExp != null && outsideExp instanceof Term) {
if (nextExp instanceof Variable) {
outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec))));
} else {
// ToDo.
}
}
String[] sideEffects = new String[] {""};
String outsideAccessor = outsideExp.toImplementation(sideEffects);
input.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field.
// Update constructor.
String initializingStatement = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter();
if (component != null) {
MethodDeclaration constructor = getConstructor(component);
constructor.addStatement(initializingStatement); // initialize the reference field.
} else {
constructorStatements.add(initializingStatement); // initialize the reference field.
}
}
}
}
}
} catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork
| InvalidMessage | UnificationFailed | ValueUndefined e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
}
}
}
return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements);
}
}