diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java index 9786f67..2b3a636 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java @@ -1,10 +1,8 @@ package application.actions; import java.awt.event.ActionEvent; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; @@ -17,12 +15,8 @@ import generators.DataTransferMethodAnalyzer; import generators.JavaSpecific; import generators.JerseyCodeGenerator; -import generators.JerseyMethodBodyGenerator; -import generators.RestApiSpecific; -import generators.StandaloneSpecific; -import models.algebra.Type; +import generators.JerseySpecific; import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; import models.dataFlowModel.DataFlowGraph; @@ -63,7 +57,7 @@ JerseyCodeGenerator.resetMainTypeName(); // use the default main type's name. } // editor.setCodes(JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model))); - editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new RestApiSpecific(), new JavaSpecific())); + editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific())); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java b/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java index 99f1561..fd57c66 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/CodeUtil.java @@ -10,34 +10,4 @@ } return newString; } - - public static String getToStringExp(String typeName, String rawExp) { - if (typeName.equals("int")) { - return "Integer.toString(" + rawExp + ")"; - } else if (typeName.equals("float")) { - return "Float.toString(" + rawExp + ")"; - } else if (typeName.equals("double")) { - return "Double.toString(" + rawExp + ")"; - } else if (typeName.equals("boolean")) { - return "Boolean.toString(" + rawExp + ")"; - } else { - return rawExp + ".toString()"; - } - } - - public static String getToValueExp(String typeName, String strExp) { - if (typeName.equals("int")) { - return "Integer.parseInt(" + strExp + ")"; - } else if (typeName.equals("float")) { - return "Float.parseFloat(" + strExp + ")"; - } else if (typeName.equals("double")) { - return "Double.parseDouble(" + strExp + ")"; - } else if (typeName.equals("boolean")) { - return "Boolean.parseBoolean(" + strExp + ")"; - } else if (typeName.startsWith("ArrayList") || typeName.startsWith("List")) { - return "Arrays.asList(" + strExp + ".replace(\"[\",\"\").replace(\"]\",\"\").split(\",\",0))"; - } else { - return strExp; - } - } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 3ce6bb8..3464845 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -317,26 +317,36 @@ return dstRes; } - protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, ILanguageSpecific langSpec) { + protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { // returns the state field when all incoming data-flow edges are PUSH-style. if (langSpec.isValueType(resStateType)) { stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; } else { if (resourceHierarchy.getChildren() != null && resourceHierarchy.getChildren().size() == 1 && resourceHierarchy.getChildren().iterator().next().getNumParameters() > 0) { // list or map - String implTypeName = resStateType.getImplementationTypeName(); - // copy the current state to be returned as a 'value' - List parameters = new ArrayList<>(); - parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); - stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); - } else { - if (resourceHierarchy.getChildren() == null || resourceHierarchy.getChildren().size() == 0) { - // a leaf resource + if (!platformSpec.isMonolithic()) { + // For REST API + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; + } else { String implTypeName = resStateType.getImplementationTypeName(); // copy the current state to be returned as a 'value' List parameters = new ArrayList<>(); parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); + } + } else { + if (resourceHierarchy.getChildren() == null || resourceHierarchy.getChildren().size() == 0) { + // a leaf resource + if (!platformSpec.isMonolithic()) { + // For REST API + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; + } else { + String implTypeName = resStateType.getImplementationTypeName(); + // copy the current state to be returned as a 'value' + List parameters = new ArrayList<>(); + parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); + } } else { Term composer = null; Term composerSub = new Constant(DataConstraintModel.nil); @@ -345,10 +355,10 @@ String childTypeName = getComponentName(child, langSpec); String fieldName = langSpec.toVariableName(childTypeName); Term childGetter = null; - if (!CodeGenerator.generatesComponent(child)) { + if (!generatesComponent(child)) { // the child is not a class - childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); - childGetter.addChild(new Constant("this")); + childGetter = new Term(new Symbol(getterPrefix + childTypeName, 1, Symbol.Type.METHOD)); + childGetter.addChild(new Constant(langSpec.getSelfExp())); } else { // the child is a class childGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 3c6160c..6bd89a9 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -9,11 +9,15 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; + +import algorithms.TypeInference; + import java.util.Set; import java.util.Stack; import code.ast.Annotation; import code.ast.Block; +import code.ast.CodeUtil; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; import code.ast.MethodDeclaration; @@ -91,15 +95,15 @@ if (component == null) { // Add compilation unit for this component. component = langSpec.newTypeDeclaration(resourceName); - if (platformSpec.hasComponentAnnotation() && resourceNode.getResourceHierarchy().getParent() == null) { + if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { // For each root node, add component annotations. - platformSpec.addComponentAnnotations(component, resourceNode.getResourceName()); + ((RestApiSpecific) platformSpec).addComponentAnnotations(component, resourceNode.getResourceName()); } resourceComponents.put(resourceNode.getResourceHierarchy(), component); CompilationUnit cu = langSpec.newCompilationUnit(component); - if (platformSpec.hasPlatformSpecificImports() && resourceNode.getResourceHierarchy().getParent() == null) { + if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { // For each root node, add platform specific imports. - platformSpec.addPlatformSpecificImports(cu); + ((RestApiSpecific) platformSpec).addPlatformSpecificImports(cu); } codes.add(cu); @@ -554,7 +558,7 @@ // Inter-service (for REST API) if (!bDeclareClientField && parentComponent != null) { // Declare a client field to connect to the destination resource of push transfer. - platformSpec.addClientFieldDeclaration(parentComponent); + ((RestApiSpecific) platformSpec).addClientFieldDeclaration(parentComponent); bDeclareClientField = true; } } else { @@ -704,7 +708,7 @@ // Inter-service (for REST API) if (!bDeclareClientField && parentComponent != null) { // Declare a client field to connect to the destination resource of push transfer. - platformSpec.addClientFieldDeclaration(parentComponent); + ((RestApiSpecific) platformSpec).addClientFieldDeclaration(parentComponent); bDeclareClientField = true; } } else { @@ -833,13 +837,13 @@ MethodDeclaration stateGetter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { // Since this getter is also an accessor. - platformSpec.addGetAnnotations(stateGetter); + ((RestApiSpecific) platformSpec).addGetAnnotations(stateGetter); } component.addMethod(stateGetter); boolean hasDescendantIn = hasDescendantInput(resourceNode); if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { - fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, langSpec); + fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, platformSpec, langSpec); } else { // invocations to other getter methods when at least one incoming data-flow edges is PULL-style. addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec); @@ -1237,19 +1241,19 @@ if (selector.getExpression() instanceof Variable) { Variable selVar = (Variable) selector.getExpression(); VariableDeclaration chParam = langSpec.newVariableDeclaration(selVar.getType(), selVar.getName()); - if (isRestAPI) platformSpec.addFormParamAnnotation(chParam, selVar.getName()); + if (isRestAPI) ((RestApiSpecific) platformSpec).addFormParamAnnotation(chParam, selVar.getName()); parameters.add(chParam); // A channel parameter to specify the context of the collaboration. } } VariableDeclaration param = langSpec.newVariableDeclaration(srcResPath.getResourceStateType(), srcResName); - if (isRestAPI) platformSpec.addFormParamAnnotation(param, srcResName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, srcResName); parameters.add(param); // The state of the source resource to carry the data-flow. // For the refs. for (ResourcePath ref: ch.getReferenceResources()) { if (!resourceNode.getInSideResources().contains(ref)) { String refName = langSpec.toVariableName(getComponentName(ref.getResourceHierarchy(), langSpec)); param = langSpec.newVariableDeclaration(ref.getResourceStateType(), refName); - if (isRestAPI) platformSpec.addFormParamAnnotation(param, refName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, refName); parameters.add(param); } } @@ -1275,22 +1279,28 @@ update = langSpec.newMethodDeclaration(updateMethodPrefix + resComponentName + from + srcResComponentName, false, null, parameters); } } + // Calculate in-degree (PUSH transfer) of the destination resource. int inDegree = 0; + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; + } + } if (isRestAPI) { // Determine whether the update method is put or post or delete. if (isPut(out)) { - platformSpec.addPutAnnotations(update); + ((RestApiSpecific) platformSpec).addPutAnnotations(update); } else { if (!isDelete(out)) { - platformSpec.addPostAnnotations(update); + ((RestApiSpecific) platformSpec).addPostAnnotations(update); } else { - platformSpec.addDeleteAnnotations(update); + ((RestApiSpecific) platformSpec).addDeleteAnnotations(update); } } - inDegree = indirectSrcChNode.getIndegree() + ch.getInputChannelMembers().size(); if (inDegree > 1) { // If incoming edges are multiple, then a child resource for each source resource is defined in the destination resource so that its state can be updated separately. - if (isRestAPI) platformSpec.addPathAnnotation(update, "/" + srcResName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathAnnotation(update, "/" + srcResName); } } if (update != null) { @@ -1302,10 +1312,82 @@ parentComponent.addMethod(update); } } - if (hasRestAPI && !isRestAPI) { - // Declare an update accessor method in the type of root resource. - declareUpdateAccessorInTheRootResource(resourceNode, update.getName(), ch, out, srcResPath, dstResPath, - rootComponent, inDegree, platformSpec, langSpec); + // For a post/put REST API. + if (hasRestAPI) { + if (!isRestAPI) { + // If not a root resource. + // Declare an update accessor method in the type of root resource. + declareUpdateAccessorInTheRootResource(resourceNode, update.getName(), ch, out, srcResPath, dstResPath, + rootComponent, inDegree, platformSpec, langSpec); + } + // to convert a json param to a tuple, pair or map object. + for (VariableDeclaration jsonParam: update.getParameters()) { + Type paramType = jsonParam.getType(); + String paramName = jsonParam.getName(); + String paramTypeName = paramType.getInterfaceTypeName(); + String strTypeName = DataConstraintModel.typeString.getInterfaceTypeName(); + String paramConverter = ""; + if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { + Type compType = TypeInference.getListComponentType(paramType); + if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getForStatementForCollection("str", strTypeName, jsonParam.getName()) + "\n"; + String mapTypeName = convertFromEntryToMapType(compType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getEndForStatement("str"); + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (DataConstraintModel.typePair.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getForStatementForCollection("str", strTypeName, jsonParam.getName()) + "\n"; + String mapTypeName = convertFromEntryToMapType(compType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToPair(compType, "i", langSpec))) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getEndForStatement("str"); + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + // To do. + } + } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { + jsonParam.setType(DataConstraintModel.typeString); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; + String mapTypeName = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + paramName + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(paramType, "i", langSpec) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getClosingScoreDelimiter(); + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (DataConstraintModel.typePair.isAncestorOf(paramType)) { + jsonParam.setType(DataConstraintModel.typeString); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; + String mapTypeName = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + paramName + langSpec.getAssignment() + getCodeForConversionFromMapToPair(paramType, "i", langSpec) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getClosingScoreDelimiter(); + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (DataConstraintModel.typeMap.isAncestorOf(paramType)) { + jsonParam.setType(DataConstraintModel.typeString); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; + String mapTypeName = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName, langSpec) + "\n"; + paramConverter += langSpec.getClosingScoreDelimiter(); + ((RestApiSpecific) platformSpec).addJsonException(update); + } + if (paramConverter.length() > 0 && !update.getBody().getStatements().contains(paramConverter)) { + update.addFirstStatement(paramConverter); + } + } } // Add a statement to update the state field @@ -1341,6 +1423,18 @@ children = descendantRes.getChildren(); } while (children != null && children.size() == 1); } + // Replace the type of the state field. + Type fieldType = getImplStateType(outRes, langSpec); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals(fieldOfResourceState)) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the update method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -1390,6 +1484,7 @@ updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); } } + // add an update statement of the state of dst side resource. if (numOfOutResourcesWithTheSameHierarchy == 1) { update.addFirstStatement(updateStatement); } else { @@ -1437,7 +1532,6 @@ } // Declare the field to cache the state of the source resource in the type of the destination resource. - inDegree = indirectSrcChNode.getIndegree() + ch.getInputChannelMembers().size(); if (inDegree > 1 || (ch.getInputChannelMembers().size() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // If incoming edges are multiple, or the current state of an input member is needed. @@ -1616,11 +1710,11 @@ if (insideResPath != null) { if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. - update.addStatement(langSpec.getForStatement(forVarName, parent)); + update.addStatement(langSpec.getForStatementForList(forVarName, parent)); addForStatement = true; } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for broadcasting. - update.addStatement(langSpec.getForStatement(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); + update.addStatement(langSpec.getForStatementForMap(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); addForStatement = true; } } @@ -1897,7 +1991,7 @@ } if (!platformSpec.isMonolithic() && !resourcePath.contains("{" + var.getName()+ "}")) { VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), var.getName()); - platformSpec.addFormParamAnnotation(param, var.getName()); + ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, var.getName()); rootInputParams.add(param); } } @@ -2302,11 +2396,11 @@ if (insideResPath != null) { if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. - input.addStatement(langSpec.getForStatement(forVarName, parent)); + input.addStatement(langSpec.getForStatementForList(forVarName, parent)); addForStatement = true; } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for broadcasting. - input.addStatement(langSpec.getForStatement(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); + input.addStatement(langSpec.getForStatementForMap(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); addForStatement = true; } } @@ -2539,9 +2633,11 @@ ResourcePath resPath = resourceNode.getPrimaryResourcePath(); Expression getState = getPullAccessor(platformSpec).getDirectStateAccessorFor(resPath, resPath.getRoot()); getterAccessor.getBody().addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null})) + langSpec.getStatementDelimiter()); - platformSpec.addGetAnnotations(getterAccessor); - if (resourcePath.length() > 0) { - platformSpec.addPathAnnotation(getterAccessor, resourcePath); + if (!platformSpec.isMonolithic()) { + ((RestApiSpecific) platformSpec).addGetAnnotations(getterAccessor); + if (resourcePath.length() > 0) { + ((RestApiSpecific) platformSpec).addPathAnnotation(getterAccessor, resourcePath); + } } rootComponent.addMethod(getterAccessor); } @@ -2558,38 +2654,70 @@ if (selector.getExpression() instanceof Variable) { Variable selVar = (Variable) selector.getExpression(); VariableDeclaration chParam = langSpec.newVariableDeclaration(selVar.getType(), selVar.getName()); - platformSpec.addFormParamAnnotation(chParam, selVar.getName()); + if (!platformSpec.isMonolithic()) { + ((RestApiSpecific) platformSpec).addFormParamAnnotation(chParam, selVar.getName()); + } parameters.add(chParam); // A channel parameter to specify the context of the collaboration. } } Type srcType = srcResPath.getResourceStateType(); String srcResName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); param = langSpec.newVariableDeclaration(srcType, srcResName); - platformSpec.addFormParamAnnotation(param, srcResName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, srcResName); parameters.add(param); // The state of the source resource to carry the data-flow. for (ResourcePath refRes: ch.getReferenceResources()) { if (!refRes.equals(resourceNode.getInSideResource(ch))) { String refName = langSpec.toVariableName(getComponentName(refRes.getResourceHierarchy(), langSpec)); param = langSpec.newVariableDeclaration(refRes.getResourceStateType(), refName); - platformSpec.addFormParamAnnotation(param, refName); + if (!platformSpec.isMonolithic()) { + ((RestApiSpecific) platformSpec).addFormParamAnnotation(param, refName); + } parameters.add(param); } } MethodDeclaration updateAccessor = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); - if (isPut(cm)) { - platformSpec.addPutAnnotations(updateAccessor); - } else { - if (!isDelete(cm)) { - platformSpec.addPostAnnotations(updateAccessor); + if (!platformSpec.isMonolithic()) { + if (isPut(cm)) { + ((RestApiSpecific) platformSpec).addPutAnnotations(updateAccessor); } else { - platformSpec.addDeleteAnnotations(updateAccessor); + if (!isDelete(cm)) { + ((RestApiSpecific) platformSpec).addPostAnnotations(updateAccessor); + } else { + ((RestApiSpecific) platformSpec).addDeleteAnnotations(updateAccessor); + } } } if (inDegree > 1) { // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. resourcePath += "/" + langSpec.toVariableName(srcResName); } - platformSpec.addPathAnnotation(updateAccessor, resourcePath); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathAnnotation(updateAccessor, resourcePath); + + // To make the accessor call the update method. + Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(cm.getResource(), cm.getResource().getRoot()); + List 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[] {""}); + int v = 0; + for (VariableDeclaration var: updateAccessor.getParameters()) { + if (v < cm.getResource().getPathParams().size()) { + if (cm.getResource().getPathParams().get(v) instanceof Variable) { + args.add(((Variable) cm.getResource().getPathParams().get(v)).getName()); + } else if (cm.getResource().getPathParams().get(v) instanceof JsonAccessor) { + args.add(((JsonAccessor) cm.getResource().getPathParams().get(v)).toImplementation(new String[] {})); // ToDo. + } + } else { + args.add(var.getName()); + } + v++; + } + updateAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, updateMethodName, args)); rootComponent.addMethod(updateAccessor); } @@ -2598,17 +2726,19 @@ TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { MethodDeclaration rootInputAccessor; rootInputAccessor = langSpec.newMethodDeclaration(inputMethodName, false, null, rootInputParams); - if (isPut(cm)) { - platformSpec.addPutAnnotations(rootInputAccessor); - } else { - if (!isDelete(cm)) { - platformSpec.addPostAnnotations(rootInputAccessor); + if (!platformSpec.isMonolithic()) { + if (isPut(cm)) { + ((RestApiSpecific) platformSpec).addPutAnnotations(rootInputAccessor); } else { - platformSpec.addDeleteAnnotations(rootInputAccessor); + if (!isDelete(cm)) { + ((RestApiSpecific) platformSpec).addPostAnnotations(rootInputAccessor); + } else { + ((RestApiSpecific) platformSpec).addDeleteAnnotations(rootInputAccessor); + } } - } - if (resourcePath.length() > 0) { - platformSpec.addPathAnnotation(rootInputAccessor, resourcePath); + if (resourcePath.length() > 0) { + ((RestApiSpecific) platformSpec).addPathAnnotation(rootInputAccessor, resourcePath); + } } rootComponent.addMethod(rootInputAccessor); } @@ -2623,14 +2753,14 @@ String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) platformSpec.addPathParamAnnotation(param, paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); pathParams.add(param); } else if (pathParam instanceof Term) { Term var = (Term) pathParam; String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) platformSpec.addPathParamAnnotation(param, paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); pathParams.add(param); } } @@ -2652,7 +2782,7 @@ } params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (isRestAPI) platformSpec.addPathParamAnnotation(param, paramName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); pathParams.add(param); } else if (pathParam instanceof Term) { Term var = (Term) pathParam; @@ -2664,7 +2794,7 @@ } params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (isRestAPI) platformSpec.addPathParamAnnotation(param, paramName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); pathParams.add(param); } v++; @@ -2683,14 +2813,14 @@ String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) platformSpec.addPathParamAnnotation(param, paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); rootInputParams.add(param); } else if (pathParam instanceof Term) { Term var = (Term) pathParam; String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) platformSpec.addPathParamAnnotation(param, paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); rootInputParams.add(param); } v++; @@ -2702,14 +2832,14 @@ String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) platformSpec.addPathParamAnnotation(param, paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); rootInputParams.add(param); } else if (pathParam instanceof Term) { Term var = (Term) pathParam; String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) platformSpec.addPathParamAnnotation(param, paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); rootInputParams.add(param); } v++; @@ -2717,4 +2847,89 @@ } return resPath.getResourceHierarchy().toResourcePath(params); } + + private static String convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { + String mapTypeName = null; + if (DataConstraintModel.typePair.isAncestorOf(type)) { + Type compType = TypeInference.getPairComponentType(type); + String wrapperType = DataConstraintModel.getWrapperType(compType); + if (wrapperType != null) { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); + } else { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compType.getInterfaceTypeName()).getInterfaceTypeName(); + } + } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { + List compTypes = TypeInference.getMapComponentTypes(type); + String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); + if (wrapperType != null) { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); + } else { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compTypes.get(1).getInterfaceTypeName()).getInterfaceTypeName(); + } + } else { + mapTypeName = type.getInterfaceTypeName(); + mapTypeName = mapTypeName.replace(DataConstraintModel.typeTuple.getInterfaceTypeName(), DataConstraintModel.typeMap.getInterfaceTypeName()); + for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { // Java specific + int to = mapTypeName.indexOf(",", idx); // Java specific + if (to > idx) { + mapTypeName = mapTypeName.substring(0, idx + 1) + DataConstraintModel.typeString.getInterfaceTypeName() + mapTypeName.substring(to); // All elements except for the last one have the string type. + } + } + } + return mapTypeName; + } + + private static String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { + String decoded = "$x"; + List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); + String elementBase = mapVar; + for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { + elementBase = langSpec.getFirstEntryFromMapExp(elementBase); // elementBase.entrySet().iterator().next() + if (elmType == DataConstraintModel.typeBoolean + || elmType == DataConstraintModel.typeInt + || elmType == DataConstraintModel.typeLong + || elmType == DataConstraintModel.typeFloat + || elmType == DataConstraintModel.typeDouble) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + String elmVal = langSpec.getStringToValueExp(elmType.getImplementationTypeName(), getKey); // Integer.parseInt(elementBase.getKey()) + decoded = decoded.replace("$x", langSpec.getPairExp(elmVal, "$x")); // new AbstractMap.SimpleEntry<>(Integer.parseInt(elementBase.getKey()), $x) + } else if (elmType == DataConstraintModel.typeString) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + decoded = decoded.replace("$x", langSpec.getPairExp(getKey, "$x")); // new AbstractMap.SimpleEntry<>(elementBase.getKey(), $x) + } else { + // To do. + } + elementBase = langSpec.getMethodInvocation(elementBase, DataConstraintModel.snd.getImplName()); // elementBase.getValue() + } + decoded = decoded.replace("$x", elementBase); + return decoded; + } + + private static String getCodeForConversionFromMapToPair(Type pairType, String mapVar, ILanguageSpecific langSpec) { + String decoded = "$x"; + decoded = decoded.replace("$x", "new Pair<>(" + mapVar + ".get(\"left\"), $x)"); + decoded = decoded.replace("$x", mapVar + ".get(\"right\")"); + return decoded; + } + + private static String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar, ILanguageSpecific langSpec) { + List elementsTypes = TypeInference.getMapComponentTypes(mapType); + Type keyType = elementsTypes.get(0); +// Type valType = elementsTypes.get(1); + String decoded = ""; + if (keyType == DataConstraintModel.typeBoolean + || keyType == DataConstraintModel.typeInt + || keyType == DataConstraintModel.typeLong + || keyType == DataConstraintModel.typeFloat + || keyType == DataConstraintModel.typeDouble) { + String keyVal = langSpec.getStringToValueExp(keyType.getImplementationTypeName(), "k"); + String getInvocation = langSpec.getMethodInvocation(mapVal, DataConstraintModel.lookup.getImplName(), List.of(keyVal)); + decoded += langSpec.getForStatementForMap("k", DataConstraintModel.typeString.getInterfaceTypeName(), mapVal) + "\n"; + decoded += "\t" + langSpec.getMethodInvocation(mapVar, DataConstraintModel.insert.getImplName(), List.of(keyVal, getInvocation)) + langSpec.getStatementDelimiter() + "\n"; + decoded += langSpec.getEndForStatement("k"); + } else if (keyType == DataConstraintModel.typeString) { + decoded += mapVar + langSpec.getAssignment() + mapVal + langSpec.getStatementDelimiter(); + } + return decoded; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index baf40f3..5e5ea4a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -27,6 +27,7 @@ String getVariableDeclaration(String typeName, String varName); String getFieldInitializer(Type type, Expression initialValue); boolean declareField(); + String getSelfExp(); String getFieldAccessor(String fieldName); String getMethodInvocation(String methodName); String getMethodInvocation(String receiverName, List parameters); @@ -35,18 +36,25 @@ String getConstructorInvocation(String componentName, List parameters); String getReturnStatement(String returnValue); String getIfStatement(Term condition, String block); - String getForStatement(String varName, String list); - String getForStatement(String varName, String varType, String map); + String getForStatementForList(String varName, String list); + String getForStatementForCollection(String varName, String varType, String collection); + String getForStatementForMap(String varName, String varType, String map); String getEndForStatement(); String getEndForStatement(String varName); String toComponentName(String name); String toVariableName(String name); String getMainComponentName(); - String getTupleGet(String tupleExp, int idx, int length); - String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars); String getAssignment(); String getStatementDelimiter(); String getStringDelimiter(); + String getOpeningScoreDelimiter(); + String getClosingScoreDelimiter(); + String getValueToStringExp(String typeName, String valueExp); + String getStringToValueExp(String typeName, String strExp); + String getPairExp(String first, String second); + String getFirstEntryFromMapExp(String map); + String getTupleGet(String tupleExp, int idx, int length); + String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars); boolean isValueType(Type type); boolean isVoidType(Type type); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java index 4e38370..c609b7a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java @@ -2,28 +2,8 @@ import java.util.List; -import code.ast.Annotation; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.ImportDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; - public interface IPlatformSpecific { boolean hasMain(); boolean isMonolithic(); boolean isDifferentTreesAsDifferentServices(); - boolean hasComponentAnnotation(); - void addComponentAnnotations(TypeDeclaration component, String resourceName); - void addGetAnnotations(MethodDeclaration getMethod); - void addPutAnnotations(MethodDeclaration getMethod); - void addPostAnnotations(MethodDeclaration getMethod); - void addDeleteAnnotations(MethodDeclaration getMethod); - void addPathAnnotation(MethodDeclaration method, String resourcePath); - void addPathParamAnnotation(VariableDeclaration var, String paramName); - void addFormParamAnnotation(VariableDeclaration var, String paramName); - void addClientFieldDeclaration(TypeDeclaration component); - boolean hasPlatformSpecificImports(); - void addPlatformSpecificImports(CompilationUnit cu); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 58eaa0f..5df4876 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -86,7 +86,6 @@ String dstResourceName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy()); TypeDeclaration srcComponent = componentMap.get(srcResourceName); TypeDeclaration dstComponent = componentMap.get(dstResourceName); -// DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); ChannelNode chNode = (ChannelNode) chToRes.getSource(); DataTransferChannel ch = chNode.getChannel(); for (ChannelMember out: ch.getOutputChannelMembers()) { @@ -209,6 +208,7 @@ updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; } } + // add an update statement of the state of dst side resource. if (numOfOutResourcesWithTheSameHierarchy == 1) { update.addFirstStatement(updateStatement); } else { @@ -249,8 +249,24 @@ update.addFirstStatement(ifStatement + "\t" + updateStatement.replace("\n", "\n\t") + "\n}"); } } - if (resToCh.getDestination().getIndegree() > 1 - || (resToCh.getDestination().getIndegree() == 1 && directDstCh.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // Calculate in-degree (PUSH transfer) of the destination resource. + int inDegree = 0; + Set inEdges = new HashSet<>(); + inEdges.addAll(chNode.getInEdges()); + for (ChannelNode ancestor: chNode.getAncestors()) { + inEdges.addAll(ancestor.getInEdges()); + } + for (ChannelNode descendant: chNode.getDescendants()) { + inEdges.addAll(descendant.getInEdges()); + } + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; + } + } + if (inDegree > 1 + || (inDegree == 1 && directDstCh.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // update a cache of src side resource (when incoming edges are multiple) String cacheStatement = "this." + JavaCodeGenerator.toVariableName(srcResourceName) + " = " + JavaCodeGenerator.toVariableName(srcResourceName) + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index dfe5850..58357f2 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -117,6 +117,11 @@ } @Override + public String getSelfExp() { + return self; + } + + @Override public String getFieldAccessor(String fieldName) { return self + "." + fieldName; } @@ -168,7 +173,7 @@ @Override public String getConstructorInvocation(String componentName, List parameters) { String invocation = "new " + componentName + "("; - if (parameters.size() > 0) { + if (parameters != null && parameters.size() > 0) { for (int i = 0; i < parameters.size(); i++) { if (i < parameters.size() - 1) { invocation += parameters.get(i) + ", "; @@ -192,12 +197,17 @@ } @Override - public String getForStatement(String varName, String list) { + public String getForStatementForList(String varName, String list) { return "for (int " + varName + getAssignment() + "0; " + varName + " < " + list + ".size(); " + varName + "++) {"; } @Override - public String getForStatement(String varName, String varType, String map) { + public String getForStatementForCollection(String varName, String varType, String collection) { + return "for (" + varType + " " + varName + ": " + collection + ") {"; + } + + @Override + public String getForStatementForMap(String varName, String varType, String map) { return "for (" + varType + " " + varName + ": " + map + ".keySet()) {"; } @@ -242,6 +252,58 @@ } @Override + public String getOpeningScoreDelimiter() { + return "{"; + } + + @Override + public String getClosingScoreDelimiter() { + return "}"; + } + + @Override + public String getValueToStringExp(String typeName, String valueExp) { + if (typeName.equals("int")) { + return "Integer.toString(" + valueExp + ")"; + } else if (typeName.equals("float")) { + return "Float.toString(" + valueExp + ")"; + } else if (typeName.equals("double")) { + return "Double.toString(" + valueExp + ")"; + } else if (typeName.equals("boolean")) { + return "Boolean.toString(" + valueExp + ")"; + } else { + return valueExp + ".toString()"; + } + } + + @Override + public String getStringToValueExp(String typeName, String strExp) { + if (typeName.equals("int")) { + return "Integer.parseInt(" + strExp + ")"; + } else if (typeName.equals("float")) { + return "Float.parseFloat(" + strExp + ")"; + } else if (typeName.equals("double")) { + return "Double.parseDouble(" + strExp + ")"; + } else if (typeName.equals("boolean")) { + return "Boolean.parseBoolean(" + strExp + ")"; + } else if (typeName.startsWith("ArrayList") || typeName.startsWith("List")) { + return "Arrays.asList(" + strExp + ".replace(\"[\",\"\").replace(\"]\",\"\").split(\",\",0))"; + } else { + return strExp; + } + } + + @Override + public String getPairExp(String first, String second) { + return getConstructorInvocation(DataConstraintModel.typeTuple.getImplementationTypeName() + "<>", List.of(first, second)); + } + + @Override + public String getFirstEntryFromMapExp(String map) { + return getMethodInvocation(map, "entrySet().iterator().next"); + } + + @Override public String getTupleGet(String tupleExp, int idx, int length) { Expression t = new Variable(tupleExp, DataConstraintModel.typeTuple); for (int i = 0; i < idx; i++) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 706eec2..7d7cf9a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -137,19 +137,8 @@ } else { // if there exists one or more reference channel member. HashMap inputResourceToStateAccessor = new HashMap<>(); - for (Edge chToRes2: dst.getInEdges()) { - DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); - for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - DataFlowEdge dIn = (DataFlowEdge) resToCh2; - ChannelMember in2 = null; - for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (((ResourceNode) dIn.getSource()).getOutSideResources().contains(cm.getResource())) { - in2 = cm; - break; - } - } - inputResourceToStateAccessor.put(in2, JerseyCodeGenerator.pushAccessor); - } + for (ChannelMember c: ch.getInputChannelMembers()) { + inputResourceToStateAccessor.put(c, JerseyCodeGenerator.pushAccessor); } for (ChannelMember c: ch.getReferenceChannelMembers()) { inputResourceToStateAccessor.put(c, JerseyCodeGenerator.refAccessor); @@ -197,6 +186,9 @@ if (JerseyCodeGenerator.generatesComponent(outRes)) { if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { updateStatement = sideEffects[0]; + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } } else { updateStatement = sideEffects[0] + "this.value = " + newState + ";"; } @@ -204,6 +196,9 @@ if (sideEffects[0] != null) { updateStatement = sideEffects[0]; updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes))); + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } } if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { Term selector = new Term(DataConstraintModel.set); @@ -266,17 +261,22 @@ update.addFirstStatement(ifStatement + "\t" + updateStatement.replace("\n", "\n\t") + "\n}"); } } - // Calculate in-degree of the destination resource. - Set inResources = new HashSet<>(); - for (ResourceNode rn: graph.getResourceNodes(out.getResource().getResourceHierarchy())) { - // ResourceNodes that have the same ResourceHierarchy. - for (Edge chToRes2: rn.getInEdges()) { - for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - inResources.add(((ResourceNode) resToCh2.getSource()).getResourceHierarchy()); - } + // Calculate in-degree (PUSH transfer) of the destination resource. + int inDegree = 0; + Set inEdges = new HashSet<>(); + inEdges.addAll(chNode.getInEdges()); + for (ChannelNode ancestor: chNode.getAncestors()) { + inEdges.addAll(ancestor.getInEdges()); + } + for (ChannelNode descendant: chNode.getDescendants()) { + inEdges.addAll(descendant.getInEdges()); + } + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; } } - int inDegree = inResources.size(); if (inDegree > 1 || (inDegree == 1 && directDstCh.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // update a cache of src side resource (when incoming edges are multiple) @@ -409,16 +409,19 @@ getter.addStatement("return " + dstResName + ";"); } } else { + String[] sideEffects = new String[] {""}; if (DataConstraintModel.typeList.isAncestorOf(dst.getParent().getResourceStateType())) { Term selector = new Term(DataConstraintModel.get); selector.addChild(new Field("value")); selector.addChild(dst.getSelectors().get(dst.getSelectors().size() - 1).getExpression()); - getter.addStatement("return " + selector.toImplementation(new String[] {}) + ";"); + String curState = selector.toImplementation(sideEffects); + getter.addStatement(sideEffects[0] + "return " + curState + ";"); } else if (DataConstraintModel.typeMap.isAncestorOf(dst.getParent().getResourceStateType())) { Term selector = new Term(DataConstraintModel.lookup); selector.addChild(new Field("value")); selector.addChild(dst.getSelectors().get(dst.getSelectors().size() - 1).getExpression()); - getter.addStatement("return " + selector.toImplementation(new String[] {}) + ";"); + String curState = selector.toImplementation(sideEffects); + getter.addStatement(sideEffects[0] + "return " + curState + ";"); } } } @@ -1466,7 +1469,7 @@ || elmType == DataConstraintModel.typeLong || elmType == DataConstraintModel.typeFloat || elmType == DataConstraintModel.typeDouble) { - String elmVal = CodeUtil.getToValueExp(elmType.getImplementationTypeName(), elementBase + ".getKey()"); + String elmVal = new JavaSpecific().getStringToValueExp(elmType.getImplementationTypeName(), elementBase + ".getKey()"); decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elmVal + ", $x)"); } else if (elmType == DataConstraintModel.typeString) { decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elementBase + ".getKey(), $x)"); @@ -1499,7 +1502,7 @@ || keyType == DataConstraintModel.typeDouble) { decoded += "for (String k: " + mapVal + ".keySet()) {\n"; decoded += "\t" + mapVar + ".put("; - keyVal = CodeUtil.getToValueExp(keyType.getImplementationTypeName(), "k"); + keyVal = new JavaSpecific().getStringToValueExp(keyType.getImplementationTypeName(), "k"); decoded += keyVal + ", " + mapVal + ".get(" + keyVal + ")" + ");\n"; decoded += "}"; } else if (keyType == DataConstraintModel.typeString) { @@ -1537,7 +1540,7 @@ // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} statements += "form.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(" + value + "));\n"; } else { - statements += "form.param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), value) + ");\n"; + statements += "form.param(\"" + paramName + "\", " + new JavaSpecific().getValueToStringExp(paramType.getImplementationTypeName(), value) + ");\n"; } } if (isFirstCall) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java new file mode 100644 index 0000000..4bb3c4b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java @@ -0,0 +1,86 @@ +package generators; + +import code.ast.Annotation; +import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; +import code.ast.ImportDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; +import models.algebra.Type; + +public class JerseySpecific extends RestApiSpecific { + public static final Type typeClient = new Type("Client", "Client"); + + public JerseySpecific() { + langSpec = new JavaSpecific(); + } + + @Override + public void addComponentAnnotations(TypeDeclaration component, String resourcePath) { + component.addAnnotation(new Annotation("Component")); + component.addAnnotation(new Annotation("Path", "\"/" + resourcePath + "\"")); + } + + @Override + public void addGetAnnotations(MethodDeclaration getMethod) { + getMethod.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); + getMethod.addAnnotation(new Annotation("GET")); + } + + @Override + public void addPutAnnotations(MethodDeclaration putMethod) { + putMethod.addAnnotation(new Annotation("PUT")); + } + + @Override + public void addPostAnnotations(MethodDeclaration postMethod) { + postMethod.addAnnotation(new Annotation("POST")); + } + + @Override + public void addDeleteAnnotations(MethodDeclaration deleteMethod) { + deleteMethod.addAnnotation(new Annotation("DELETE")); + } + + @Override + public void addPathAnnotation(MethodDeclaration method, String resourcePath) { + method.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); + } + + @Override + public void addPathParamAnnotation(VariableDeclaration var, String paramName) { + var.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + } + + @Override + public void addFormParamAnnotation(VariableDeclaration var, String paramName) { + var.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); + } + + @Override + public void addClientFieldDeclaration(TypeDeclaration component) { + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + component.addField(clientField); + } + + @Override + public void addPlatformSpecificImports(CompilationUnit cu) { + cu.addImport(new ImportDeclaration("javax.ws.rs.*")); + cu.addImport(new ImportDeclaration("javax.ws.rs.client.*")); + cu.addImport(new ImportDeclaration("javax.ws.rs.core.*")); + cu.addImport(new ImportDeclaration("org.springframework.stereotype.Component")); + cu.addImport(new ImportDeclaration("com.fasterxml.jackson.databind.ObjectMapper")); + cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); + } + + @Override + public String getConversionFromJsonString(String fromStrVarName, String toVarName, String toVarType) { + return toVarType + toVarName + langSpec.getAssignment() + langSpec.getConstructorInvocation("ObjectMapper", null) + ".readValue(" + fromStrVarName + ", HashMap.class)"; + } + + @Override + public void addJsonException(MethodDeclaration method) { + method.addThrow("JsonProcessingException"); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java index b5af7f5..f8aeb83 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java @@ -12,8 +12,8 @@ import code.ast.VariableDeclaration; import models.algebra.Type; -public class RestApiSpecific implements IPlatformSpecific { - public static final Type typeClient = new Type("Client", "Client"); +abstract public class RestApiSpecific implements IPlatformSpecific { + protected ILanguageSpecific langSpec = null; @Override public boolean hasMain() { @@ -30,71 +30,27 @@ return true; } - @Override - public boolean hasComponentAnnotation() { - return true; - } + abstract public void addComponentAnnotations(TypeDeclaration component, String resourcePath); - @Override - public void addComponentAnnotations(TypeDeclaration component, String resourcePath) { - component.addAnnotation(new Annotation("Component")); - component.addAnnotation(new Annotation("Path", "\"/" + resourcePath + "\"")); - } + abstract public void addGetAnnotations(MethodDeclaration getMethod); - @Override - public void addGetAnnotations(MethodDeclaration getMethod) { - getMethod.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); - getMethod.addAnnotation(new Annotation("GET")); - } + abstract public void addPutAnnotations(MethodDeclaration putMethod); - @Override - public void addPutAnnotations(MethodDeclaration putMethod) { - putMethod.addAnnotation(new Annotation("PUT")); - } + abstract public void addPostAnnotations(MethodDeclaration postMethod); - @Override - public void addPostAnnotations(MethodDeclaration postMethod) { - postMethod.addAnnotation(new Annotation("POST")); - } + abstract public void addDeleteAnnotations(MethodDeclaration deleteMethod); - @Override - public void addDeleteAnnotations(MethodDeclaration deleteMethod) { - deleteMethod.addAnnotation(new Annotation("DELETE")); - } - - @Override - public void addPathAnnotation(MethodDeclaration method, String resourcePath) { - method.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); - } + abstract public void addPathAnnotation(MethodDeclaration method, String resourcePath); - @Override - public void addPathParamAnnotation(VariableDeclaration var, String paramName) { - var.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - } + abstract public void addPathParamAnnotation(VariableDeclaration var, String paramName); - @Override - public void addFormParamAnnotation(VariableDeclaration var, String paramName) { - var.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); - } + abstract public void addFormParamAnnotation(VariableDeclaration var, String paramName); + + abstract public void addClientFieldDeclaration(TypeDeclaration component); + + abstract public void addPlatformSpecificImports(CompilationUnit cu); - @Override - public void addClientFieldDeclaration(TypeDeclaration component) { - FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - component.addField(clientField); - } + abstract public String getConversionFromJsonString(String fromStrVarName, String toVarName, String toVarType); - @Override - public boolean hasPlatformSpecificImports() { - return true; - } - - @Override - public void addPlatformSpecificImports(CompilationUnit cu) { - cu.addImport(new ImportDeclaration("javax.ws.rs.*")); - cu.addImport(new ImportDeclaration("javax.ws.rs.client.*")); - cu.addImport(new ImportDeclaration("javax.ws.rs.core.*")); - cu.addImport(new ImportDeclaration("org.springframework.stereotype.Component")); - cu.addImport(new ImportDeclaration("com.fasterxml.jackson.databind.ObjectMapper")); - cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); - } + abstract public void addJsonException(MethodDeclaration method); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java index a1fc80e..ce4acd5 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java @@ -25,55 +25,4 @@ public boolean isDifferentTreesAsDifferentServices() { return false; // meaningless } - - @Override - public boolean hasComponentAnnotation() { - return false; - } - - @Override - public void addComponentAnnotations(TypeDeclaration component, String resourcePath) { - } - - @Override - public void addGetAnnotations(MethodDeclaration getMethod) { - } - - @Override - public void addPutAnnotations(MethodDeclaration getMethod) { - } - - @Override - public void addPostAnnotations(MethodDeclaration getMethod) { - } - - @Override - public void addDeleteAnnotations(MethodDeclaration getMethod) { - } - - @Override - public void addPathAnnotation(MethodDeclaration method, String resourcePath) { - } - - @Override - public void addPathParamAnnotation(VariableDeclaration var, String paramName) { - } - - @Override - public void addFormParamAnnotation(VariableDeclaration var, String paramName) { - } - - @Override - public void addClientFieldDeclaration(TypeDeclaration component) { - } - - @Override - public boolean hasPlatformSpecificImports() { - return false; - } - - @Override - public void addPlatformSpecificImports(CompilationUnit cu) { - } - }