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); } }