diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index a3d2687..08739af 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -375,7 +375,7 @@ Map channelsIn = new HashMap<>(); Map channelsOut = new HashMap<>(); - Map resources = new HashMap<>(); + Map resources = new HashMap<>(); // create channel vertices for (ChannelNode c: dataFlowGraph.getRootChannelNodes()) { @@ -455,7 +455,7 @@ Object resource = graph.insertVertex(parent, null, res.getResourceName(), 20, 20, w, h, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex - resources.put(res, resource); + resources.put(System.identityHashCode(res), resource); getChildResource(resource, resNode, resources, w, h); } @@ -466,7 +466,7 @@ // output edge DataTransferChannel channel = ((ChannelNode) dfEdge.getSource()).getChannel(); ResourcePath dstRes = ((ResourceNode) dfEdge.getDestination()).getOutSideResource(); - graph.insertEdge(parent, null, new SrcDstAttribute(channel, dstRes), channelsOut.get(channel), resources.get(dstRes), "movable=false"); + graph.insertEdge(parent, null, new SrcDstAttribute(channel, dstRes), channelsOut.get(channel), resources.get(System.identityHashCode(dstRes)), "movable=false"); } else { // input edge ResourcePath srcRes = ((ResourceNode) dfEdge.getSource()).getOutSideResource(); @@ -474,10 +474,11 @@ Set> toRes = getResourceDependencyForChannel(channel, model, dataFlowGraph); for(Map.Entry RtoR : toRes) { graph.insertEdge(parent, null, null, - resources.get(RtoR.getValue().getOutSideResource()), resources.get(RtoR.getKey().getOutSideResource()), "dashed=true;movable=false"); + resources.get(System.identityHashCode(RtoR.getValue().getOutSideResource())), + resources.get(System.identityHashCode(RtoR.getKey().getOutSideResource())), "dashed=true;movable=false"); } - graph.insertEdge(parent, null, new SrcDstAttribute(srcRes, channel), resources.get(srcRes), channelsIn.get(channel), "movable=false"); + graph.insertEdge(parent, null, new SrcDstAttribute(srcRes, channel), resources.get(System.identityHashCode(srcRes)), channelsIn.get(channel), "movable=false"); } } @@ -485,19 +486,19 @@ // reference edges DataTransferChannel channel = (DataTransferChannel) ch; for (ResourcePath refRes: channel.getReferenceResources()) { - graph.insertEdge(parent, null, null, resources.get(refRes), channelsIn.get(channel), "dashed=true;movable=false"); + graph.insertEdge(parent, null, null, resources.get(System.identityHashCode(refRes)), channelsIn.get(channel), "dashed=true;movable=false"); } } } finally { graph.getModel().endUpdate(); } -// setTreeLayout(); + setDAGLayout(); bReflectingArchitectureModel = false; return graph; } - public void getChildResource(Object resource, ResourceNode resNode, Map resources, int w, int h) { + public void getChildResource(Object resource, ResourceNode resNode, Map resources, int w, int h) { for (ResourceNode c: resNode.getChildren()) { // w = w - 100; @@ -509,7 +510,7 @@ Object chResource = graph.insertVertex(resource, null, chRes.getName(), 0, 0, w, h, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex - resources.put(chRes, chResource); + resources.put(System.identityHashCode(chRes), chResource); getChildResource(chResource, c, resources, w, h); } } @@ -796,9 +797,11 @@ Map>> dependency = ch.fillOutsideResourcePaths(ch.getOutputChannelMembers().iterator().next(), JavaCodeGenerator.pullAccessor); for (ChannelMember srcMem: dependency.keySet()) { ResourceNode srcNode = dataFlowGraph.getResourceNode(srcMem.getResource()); - for (ChannelMember dstMem: dependency.get(srcMem).getValue()) { - ResourceNode dstNode = dataFlowGraph.getResourceNode(dstMem.getResource()); - resourceDpendency.add(new AbstractMap.SimpleEntry<>(srcNode, dstNode)); + if (srcNode != null) { + for (ChannelMember dstMem: dependency.get(srcMem).getValue()) { + ResourceNode dstNode = dataFlowGraph.getResourceNode(dstMem.getResource()); + resourceDpendency.add(new AbstractMap.SimpleEntry<>(srcNode, dstNode)); + } } } } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage diff --git a/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java b/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java index 62c120e..ddb1428 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java +++ b/AlgebraicDataflowArchitectureModel/src/application/layouts/DAGLayout.java @@ -67,7 +67,7 @@ public void execute(Object parent) { graphModel.beginUpdate(); try { - // ���f������resource, channel, eventChannel�ɕ����� + // ���f������resource, channel, eventChannel�ɕ����� for (int i = 0; i < graphModel.getChildCount(parent); i++) { mxCell cell = (mxCell) graphModel.getChildAt(parent, i); @@ -75,7 +75,7 @@ mxCellState state = view.getState(cell); cells.add(cell); - // cell��resource�ł��� + // cell��resource�ł��� if ("ellipse".equals(state.getStyle().get("shape"))) { roots.add(cell); hierarchicalRecursionOrder.put(cell, new ArrayList<>()); @@ -87,20 +87,31 @@ continue; } - // cell��eventChannel�ł��� + // cell��eventChannel�ł��� if (cell.getEdgeCount() == 1) { eventChannels.add(cell); hierarchicalRecursionOrder.put(cell, new ArrayList<>()); } else { - // cell��channel�ł��� - channels.add(cell); + // cell��channel�ł��� + boolean bEventChannel = true; + for (int j = 0; j < cell.getEdgeCount(); j++) { + mxCell edge = (mxCell) cell.getEdgeAt(j); + if (edge.getTarget() == cell) { + bEventChannel = false; + } + } + if (bEventChannel) { + eventChannels.add(cell); + } else { + channels.add(cell); + } hierarchicalRecursionOrder.put(cell, new ArrayList<>()); } } } } - // �S�Ă�cell�̍��W�A�傫���Ȃǂ������� + // �S�Ă�cell�̍��W�A�傫���Ȃǂ������� for (mxCell c : cells) { c.getGeometry().setX(0); c.getGeometry().setY(0); @@ -112,22 +123,22 @@ } } - // dotEdges�������� + // dotEdges�������� for (mxCell c : cells) { dotEdges.put(c, new HashSet<>()); } - // line���\�z���� + // line���\�z���� for (mxCell ec : eventChannels) { List newline = new ArrayList(); lines.add(newline); constructionLine(ec, 0); } - // cell�̐[�����Čv�Z + // cell�̐[�����Čv�Z reculcDist(); - // cell��������line��index�����߂� + // cell��������line��index�����߂� for (int i = 0; i < lines.size(); i++) { for (mxCell cell : lines.get(i)) { if (cellToLineIndex.get(cell) == null) { @@ -137,10 +148,10 @@ } } - // ���ׂ�line�̏��Ԃ��\�[�g���� + // ���ׂ�line�̏��Ԃ��\�[�g���� sortLines(); - // cell��z�u���� + // cell��z�u���� layout((mxCell) parent); } finally { @@ -148,7 +159,7 @@ } } - // �K�w�\�����ċA�I�ɒT�� + // �K�w�\�����ċA�I�ɒT�� public void familySearch(mxCell r, mxCell p, int d) { int childNum = graphModel.getChildCount(p); @@ -166,42 +177,42 @@ } } - // line���\�z���� + // line���\�z���� public void constructionLine(mxCell cur, int d) { - // vertexToDist{key : cell, value : �[��} �������� + // vertexToDist{key : cell, value : �[��} �������� if (vertexToDist.get(cur) == null) { vertexToDist.put(cur, d); } else { - // ���g���܂܂��line�̒��ň�ԑ傫���[����ۑ� + // ���g���܂܂��line�̒��ň�ԑ傫���[����ۑ� vertexToDist.put(cur, Math.max(vertexToDist.get(cur), d)); } lines.get(lines.size() - 1).add(cur); - int tagCount = 0; // edge�̎n�_�ƂȂ�cell�Ƃ��ĎQ�Ƃ��ꂽ�� + int tagCount = 0; // edge�̎n�_�ƂȂ�cell�Ƃ��ĎQ�Ƃ��ꂽ�� for (int i = 0; i < cur.getEdgeCount(); i++) { mxCell edge = (mxCell) cur.getEdgeAt(i); mxCellState state = view.getState(edge); mxCell target = (mxCell) edge.getTarget(); - // cur���n�_�ƂȂ�edge�̏I�_�ƂȂ�target�����g�A�������͑��݂��Ȃ��ꍇ������ + // cur���n�_�ƂȂ�edge�̏I�_�ƂȂ�target�����g�A�������͑��݂��Ȃ��ꍇ������ if ((cur != target) && (target != null)) { - // edge�̎�ނ�"dashed"�̏ꍇ + // edge�̎�ނ�"dashed"�̏ꍇ if ("true".equals(state.getStyle().get("dashed"))) { - state.getStyle().put("strokeColor", "#800080"); // edge�̐F��ύX - dotEdges.get(cur).add(target); // dotEdges{key : �n�_�ƂȂ�cell, value : �I�_�ƂȂ�cell} + state.getStyle().put("strokeColor", "#800080"); // edge�̐F��ύX + dotEdges.get(cur).add(target); // dotEdges{key : �n�_�ƂȂ�cell, value : �I�_�ƂȂ�cell} } else { tagCount++; - // �n�_�Ƃ��ĕ�����Q�Ƃ���Ă���ꍇ + // �n�_�Ƃ��ĕ�����Q�Ƃ���Ă���ꍇ if (tagCount > 1) { - // cur�܂ł�line�̏����č\�z���āA��������V����line���\�z���� + // cur�܂ł�line�̏����č\�z���āA��������V����line���\�z���� List newline = new ArrayList(lines.get(lines.size() - 1)); while (newline.get(newline.size() - 1).getId() != cur.getId()) { newline.remove(newline.size() - 1); } lines.add(newline); constructionLine(target, d + 1); - // �n�_�Ƃ��ď��߂ĎQ�Ƃ��ꂽ�ꍇ + // �n�_�Ƃ��ď��߂ĎQ�Ƃ��ꂽ�ꍇ } else { constructionLine(target, d + 1); } @@ -210,13 +221,13 @@ } } - // cell�̐[�����Čv�Z���� + // cell�̐[�����Čv�Z���� public void reculcDist() { boolean isChanging = false; - // �[���̍X�V���s���Ȃ��Ȃ�܂ŌJ��Ԃ� + // �[���̍X�V���s���Ȃ��Ȃ�܂ŌJ��Ԃ� while (true) { - // �����line�Ɋ܂܂�鎩�g��1�Ž�O�̐[���Ǝ��g�̐[�����r���āA�������[�����v�Z + // �����line�Ɋ܂܂�鎩�g��1�Ž�O�̐[���Ǝ��g�̐[�����r���āA�������[�����v�Z for (List line : lines) { for (int i = 1; i < line.size(); i++) { mxCell cur = line.get(i); @@ -230,7 +241,7 @@ } } - // �K�w�\�����l������cell�̐[�����v�Z + // �K�w�\�����l������cell�̐[�����v�Z for (mxCell r : roots) { for (mxCell c : hierarchicalRecursionOrder.get(r)) { mxCell p = (mxCell) graphModel.getParent(c); @@ -245,28 +256,28 @@ } } - // 1�x���ύX�������ƃ��[�v�𔲂��� + // 1�x���ύX�������ƃ��[�v�𔲂��� if (!isChanging) { break; } } } - // line���\�[�g����(�������A���ۂɂ�lines���̗v�f�̏��Ԃ͓���ւ����A�Ăяo�����Ԃ�ۑ�����order���쐬) + // line���\�[�g����(�������A���ۂɂ�lines���̗v�f�̏��Ԃ͓���ւ����A�Ăяo�����Ԃ�ۑ�����order���쐬) public void sortLines() { for (int i = 0; i < lines.size(); i++) { List line = lines.get(i); - // eventChannel����̏o�͐悪root�ł���ꍇ + // eventChannel����̏o�͐悪root�ł���ꍇ if (roots.contains(line.get(1))) { for (mxCell c : line) { - addLine(c); // order��line��index���i�[���� + addLine(c); // order��line��index���i�[���� } } } } - // order��line��index���i�[���� + // order��line��index���i�[���� public void addLine(mxCell c) { if (cellToLineIndex.get(c) != null) { for (int i : cellToLineIndex.get(c)) { @@ -277,17 +288,17 @@ } } - // root��������line��index���i�[������A�q����������line��index�������i�[���� + // root��������line��index���i�[������A�q����������line��index�������i�[���� for (int i = 0; i < graphModel.getChildCount(c); i++) { mxCell child = (mxCell) graphModel.getChildAt(c, i); addLine(child); } } - // cell��z�u���� + // cell��z�u���� public void layout(mxCell s) { - /* cell�̍��W�́Acell��parent�̍���̍��W�����x��y���ǂꂾ�����炷���Œ�`����Ă��� - ����Čv�Z�̓s����Aid=1 ��cell(���C�A�E�g���)�̍������ɂ������W��ۑ����Ă��� */ + /* cell�̍��W�́Acell��parent�̍���̍��W�����x��y���ǂꂾ�����炷���Œ�`����Ă��� + ����Čv�Z�̓s����Aid=1 ��cell(���C�A�E�g���)�̍������ɂ������W��ۑ����Ă��� */ Set movedSet = new HashSet<>(); List movedList = new ArrayList<>(); @@ -298,12 +309,12 @@ putCellGeo(s, 0, 0); - // �[���̍ő�l�����߂� + // �[���̍ő�l�����߂� for (mxCell c : cells) { maxD = Math.max(maxD, vertexToDist.get(c)); } - // ������ + // ������ distToMaxX.put(-1, 0.0); for (int d = 0; d <= maxD; d++) { movedMap.put(d, new ArrayList<>()); @@ -311,28 +322,28 @@ } for (int i : order) { - double centerY = -1; // �z�u�\���y���W(����) + double centerY = -1; // �z�u�\���y���W(����) for (mxCell cur : lines.get(i)) { - // ���ɔz�u�ς݂Ȃ�X�L�b�v + // ���ɔz�u�ς݂Ȃ�X�L�b�v if (movedSet.contains(cur)) { continue; } - int d = vertexToDist.get(cur); // cur�̐[�� - double x = distToMaxX.get(d - 1) + MOVE_X; // �z�u�\���x���W - double endX = 0; // �z�u����cell�̉E�[��x���W - double endY = 0; // �z�u����cell�̉��[��y���W + int d = vertexToDist.get(cur); // cur�̐[�� + double x = distToMaxX.get(d - 1) + MOVE_X; // �z�u�\���x���W + double endX = 0; // �z�u����cell�̉E�[��x���W + double endY = 0; // �z�u����cell�̉��[��y���W - // cur��root, channel, eventChannel�ɑ�����cell�ł���ꍇ + // cur��root, channel, eventChannel�ɑ�����cell�ł���ꍇ if (roots.contains(cur) || channels.contains(cur) || eventChannels.contains(cur)) { if (centerY == -1) { centerY = maxY + MOVE_Y + cur.getGeometry().getHeight() / 2; } - double y = centerY - cur.getGeometry().getHeight() / 2; // �z�u�\���y���W + double y = centerY - cur.getGeometry().getHeight() / 2; // �z�u�\���y���W double ny = y; double nx = x; - // �\�肵�Ă�����W�ɔz�u����Ƒ��̃��\�[�X�����ɔz�u����Ă��܂��ꍇ�A���ɂ��炷 + // �\�肵�Ă�����W�ɔz�u����Ƒ��̃��\�[�X�����ɔz�u����Ă��܂��ꍇ�A���ɂ��炷 for (mxCell m : movedSet) { if (roots.contains(m) || channels.contains(m)) { if (cellOverlap(m.getGeometry().getX(), m.getGeometry().getY(), m.getGeometry().getWidth(), m.getGeometry().getHeight(), x, y, cur.getGeometry().getWidth(), cur.getGeometry().getHeight())) { @@ -341,7 +352,7 @@ } } - // �\��̍��W�ɔz�u���āA�e�폈�����s�� + // �\��̍��W�ɔz�u���āA�e�폈�����s�� cur.getGeometry().setX(nx); cur.getGeometry().setY(ny); endX = nx + cur.getGeometry().getWidth(); @@ -350,26 +361,26 @@ addMoved(movedSet, movedList, movedMap, cur, d); graphModel.setGeometry(cur, (mxGeometry) cur.getGeometry().clone()); - // �[����d�̍ő��x���W���X�V�����ꍇ�A���ɔz�u�ς݂�cell������ɉ����ĉE�ɂ��炷 + // �[����d�̍ő��x���W���X�V�����ꍇ�A���ɔz�u�ς݂�cell������ɉ����ĉE�ɂ��炷 if (distToMaxX.get(d) < endX) { updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); } - maxY = Math.max(maxY, endY); // �z�u�ς݂�cell�̒��ł̉��[�̍��W�̍ő� + maxY = Math.max(maxY, endY); // �z�u�ς݂�cell�̒��ł̉��[�̍��W�̍ő� - // root�̎q�����܂Ƃ߂Ĕz�u���� + // root�̎q�����܂Ƃ߂Ĕz�u���� for (mxCell c : hierarchicalRecursionOrder.get(cur)) { d = vertexToDist.get(c); - nx = x; // �z�u�\���x���W + nx = x; // �z�u�\���x���W mxCell parent = (mxCell) graphModel.getParent(c); - // �[�����e�Ɠ������ꍇ�A�e��x���W��菭���傫������ + // �[�����e�Ɠ������ꍇ�A�e��x���W��菭���傫������ if (d == vertexToDist.get(parent)) { nx = cellGeo.get(parent).get("x") + MARGIN_WIDTH; } else { nx = distToMaxX.get(d - 1) + MOVE_X; } - // �z�u�ς݂Ő[�����������Z�킪�v��ꍇ�A���ɂ��炷 + // �z�u�ς݂Ő[�����������Z�킪�v��ꍇ�A���ɂ��炷 double brotherMaxY = MOVE_Y; for (int k = 0; k < graphModel.getChildCount(parent); k++) { mxCell child = (mxCell) graphModel.getChildAt(parent, k); @@ -382,7 +393,7 @@ } } - // �\��̍��W�ɔz�u���āA�e�폈�����s�� + // �\��̍��W�ɔz�u���āA�e�폈�����s�� c.getGeometry().setX(nx - cellGeo.get(parent).get("x")); c.getGeometry().setY(brotherMaxY); graphModel.setGeometry(c, (mxGeometry) c.getGeometry().clone()); @@ -391,9 +402,9 @@ endX = cellGeo.get(c).get("x") + c.getGeometry().getWidth(); endY = cellGeo.get(c).get("y") + c.getGeometry().getHeight(); - endY = resize(parent, endX, endY); // �q�����e�̓����Ɋ܂܂�Ȃ��ꍇ�A�e�̑傫����ύX���� + endY = resize(parent, endX, endY); // �q�����e�̓����Ɋ܂܂�Ȃ��ꍇ�A�e�̑傫����ύX���� - // �[����d�̍ő��x���W���X�V�����ꍇ�A���ɔz�u�ς݂�cell������ɉ����ĉE�ɂ��炷 + // �[����d�̍ő��x���W���X�V�����ꍇ�A���ɔz�u�ς݂�cell������ɉ����ĉE�ɂ��炷 if (distToMaxX.get(vertexToDist.get(c)) < endX) { updateDistToMaxX(distToMaxX, movedSet, movedMap, d, maxD, endX); } @@ -403,7 +414,7 @@ } } - // �_���̕ӂ��d�Ȃ��Ă���ꍇ�A�E�ɂ��炷 + // �_���̕ӂ��d�Ȃ��Ă���ꍇ�A�E�ɂ��炷 for (mxCell c : resources) { for (mxCell cc : dotEdges.get(c)) { for (Map.Entry> entry : dotEdges.entrySet()) { @@ -427,7 +438,7 @@ } } - // eventChannel���o�͐��y���W�ɑ����� + // eventChannel���o�͐��y���W�ɑ����� for (int i : order) { mxCell cur = lines.get(i).get(1); List ecs = new ArrayList<>(); @@ -460,7 +471,7 @@ } } - // ����resource�ɕ�����eventChannel���o�͂��Ă���ꍇ�A�d�Ȃ��Ă��܂��̂ʼn��ɂ��炷 + // ����resource�ɕ�����eventChannel���o�͂��Ă���ꍇ�A�d�Ȃ��Ă��܂��̂ʼn��ɂ��炷 Map> ecToLineIndex = new HashMap<>(); for (mxCell ec : eventChannels) { ecToLineIndex.put(ec, new ArrayList<>()); @@ -540,7 +551,7 @@ mm.get(d).add(c); } - // 2�‚̕ӂ��d�Ȃ��Ă��邩���� + // 2�‚̕ӂ��d�Ȃ��Ă��邩���� public boolean isStraightLine(double []u1, double []v1, double []u2, double []v2) { double gradient1 = 0; double length1 = Math.pow(u1[0] - v1[0], 2) + Math.pow(u1[1] - v1[1], 2); @@ -601,7 +612,7 @@ } } - // 2�‚�resource���d�Ȃ��Ă��邩���� + // 2�‚�resource���d�Ȃ��Ă��邩���� public boolean cellOverlap(double ax, double ay, double aw, double ah, double bx, double by, double bw, double bh) { if (((ax <= bx) && (bx <= ax + aw)) || ((bx <= ax) && (ax <= bx + bw))) { if (((ay <= by) && (by <= ay + ah)) || ((by <= ay) && (ay <= by + bh))) { @@ -611,7 +622,7 @@ return false; } - // �[�����Ƃ̍ő��x���W���ύX���ꂽ�Ƃ��̏��� + // �[�����Ƃ̍ő��x���W���ύX���ꂽ�Ƃ��̏��� public void updateDistToMaxX(Map distToMaxX, Set movedSet, Map> movedMap, int d, int md, double endX) { double preEndX = distToMaxX.get(d); distToMaxX.replace(d, endX); @@ -647,7 +658,7 @@ } } - // �e�̑傫����ύX + // �e�̑傫����ύX public double resize(mxCell ancestor, double endX, double endY) { while (true) { boolean isChanging = false; @@ -676,7 +687,7 @@ return endY; } - // x���W��ύX + // x���W��ύX public void relocateX(mxCell c, double nx, double dx) { c.getGeometry().setX(nx - dx); graphModel.setGeometry(c, (mxGeometry) c.getGeometry().clone()); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 06ebf11..eb84521 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -52,7 +52,9 @@ public static final String fieldOfResourceState = "value"; public static final String getterPrefix = "get"; public static final String getterOfResourceState = "getValue"; - public static final String updateMethodName = "update"; + public static final String updateMethodPrefix = "update"; + public static final String from = "From"; + public static final String _for = "For"; private static String mainTypeName = null; private static ILanguageSpecific langSpec = null; @@ -451,7 +453,7 @@ protected MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, Map>> dataFlowInform, ILanguageSpecific langSpec) { List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); - String methodName = updateMethodName; + String methodName = updateMethodPrefix; for (ResourceNode rn: passedResoueces) { methodName += langSpec.toComponentName(rn.getResourceName()); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index ea45a55..c18bfc2 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -66,6 +66,7 @@ if (generatesComponent(resourceNode.getResourceHierarchy())) { // A component will be generated for this resource. String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); + Type resStateType = getImplStateType(resourceNode.getResourceHierarchy(), langSpec); component = resourceComponents.get(resourceNode.getResourceHierarchy()); List depends = new ArrayList<>(); if (component == null) { @@ -92,6 +93,20 @@ } else { resourceConstructors.put(resourceNode.getResourceHierarchy(), constructor); } + + // Declare the field to store the state in this resource. + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + declareStateField(resourceNode, resourceName, component, resStateType, constructorParams, langSpec); + } + + // Declare the getter method in this resource to obtain the state. + MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType, langSpec); + + // Declare the accessor method in the main component to call the getter method. + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, langSpec); + + // Declare the getter methods in this resource to obtain the children resources. + declareChildGetterMethod(resourceNode, component, langSpec); } } } @@ -104,16 +119,7 @@ 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); + component = resourceComponents.get(resourceNode.getResourceHierarchy()); } if (resourceNode.getResourceHierarchy().getParent() != null) { parentComponent = resourceComponents.get(resourceNode.getResourceHierarchy().getParent()); @@ -137,10 +143,14 @@ } // 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); + if (component == null) { + MethodDeclaration stateGetter = declareStateGetterMethodInParent(resourceNode, parentComponent, resStateType, langSpec); + + if (stateGetter != null) { + // 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, Map>> initStatementsAndInputUpdates = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, model, langSpec); @@ -477,139 +487,155 @@ } } - private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, Type resStateType, ILanguageSpecific langSpec) { + + private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, 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 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); - } - } + MethodDeclaration stateGetter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); + component.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); - } + fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, 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 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(); - } + addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, langSpec); } return stateGetter; } + private MethodDeclaration declareStateGetterMethodInParent(ResourceNode resourceNode, TypeDeclaration parentComponent, Type resStateType, ILanguageSpecific langSpec) { + // Check duplication. + String getterName = getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec); + for (MethodDeclaration method: parentComponent.getMethods()) { + if (method.getName().equals(getterName)) return null; + } + + // Declare the getter method of the resource state. + List 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++; + } + MethodDeclaration stateGetter = null; + if (getterParams.size() == 0) { + stateGetter = new MethodDeclaration(getterName, resStateType); + } else { + stateGetter = new MethodDeclaration(getterName, false, resStateType, getterParams); + } + if (parentComponent != null) { + parentComponent.addMethod(stateGetter); + } + + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + fillChildGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resourceNode.getResourceHierarchy().getParent().getResourceStateType(), langSpec); + } else { + addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, langSpec); + } + + return stateGetter; + } + + private void addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode, + ILanguageSpecific langSpec) { + boolean isContainedPush = false; + DataTransferChannel ch = null; + HashMap 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(); + } + } + private void declareChildGetterMethod(ResourceNode resourceNode, TypeDeclaration component, ILanguageSpecific langSpec) { // Declare the getter methods in this resource to obtain the children resources. + Set children = new HashSet<>(); for (ResourceNode child: resourceNode.getChildren()) { if (generatesComponent(child.getResourceHierarchy())) { // A component for the child is generated. - List 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)); + if (!children.contains(child.getResourceHierarchy())) { + children.add(child.getResourceHierarchy()); + List 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++; } - 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); } - 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, Map>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, ILanguageSpecific langSpec) { // Declare cash fields and update methods in the component. - String resComponentName = langSpec.toComponentName(resourceNode.getResourceName()); + String resComponentName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); List constructorStatements = new ArrayList<>(); Map> updateStatements = new HashMap<>(); for (Edge chToRes: resourceNode.getInEdges()) { @@ -617,8 +643,8 @@ 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); + String srcResComponentName = getComponentName(srcRes.getResourceHierarchy(), langSpec); + String srcResName = langSpec.toVariableName(srcResComponentName); // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: ch.getInputChannelMembers()) { @@ -639,10 +665,12 @@ vars.add(langSpec.newVariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); } } - MethodDeclaration update = langSpec.newMethodDeclaration(updateMethodName + srcResComponentName, false, null, vars); + MethodDeclaration update = null; if (component != null) { + update = langSpec.newMethodDeclaration(updateMethodPrefix + from + srcResComponentName, false, null, vars); component.addMethod(update); } else if (parentComponent != null) { + update = langSpec.newMethodDeclaration(updateMethodPrefix + resComponentName + from + srcResComponentName, false, null, vars); parentComponent.addMethod(update); } @@ -675,18 +703,50 @@ break; } } - // Add statements to the input method. + // Add statements to the update method. String[] sideEffects = new String[] {""}; - String curState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; + String newState = updateExp.toImplementation(sideEffects); + if (generatesComponent(outRes)) { + 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(); // this.value = ... + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + update.addFirstStatement(updateStatement); + } } else { - updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + curState + langSpec.getStatementDelimiter(); // this.value = ... + String updateStatement = ""; + if (sideEffects[0] != null) { + updateStatement = sideEffects[0]; + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + } + if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += 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(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + update.addFirstStatement(updateStatement); + } } - if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { - update.addFirstStatement(updateStatement); - } break; } } @@ -824,9 +884,26 @@ params.add(refVarName); } } - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) chToRes2.getDestination()).getResourceName()), - updateMethodName + resComponentName, - params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); + if (!generatesComponent(srcRes2)) { + srcRes2 = srcRes2.getParent(); + } + String updateMethodName = null; + ResourceHierarchy dstRes = ((ResourceNode) chToRes2.getDestination()).getResourceHierarchy(); + if (!generatesComponent(dstRes)) { + updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; + dstRes = dstRes.getParent(); + } else { + updateMethodName = updateMethodPrefix + from + resComponentName; + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (srcRes2 != dstRes) { + update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, params) + + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + } else { + update.addStatement(langSpec.getMethodInvocation(updateMethodName, params) + + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); + } } } if (outsideInputMembers2.size() > 0) { @@ -955,10 +1032,23 @@ } else { // var has not come from a reference resource. resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + boolean bExists = false; + for (VariableDeclaration mainParam: mainInputParams) { + if (mainParam.getName().equals(var.getName()) ) { + bExists = true; + break; + } + } + if (!bExists) { + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } } } - input = langSpec.newMethodDeclaration(((Term) message).getSymbol().getImplName(), false, null, resInputParams); + String inputMethodName = ((Term) message).getSymbol().getImplName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += _for + getComponentName(out.getResource().getResourceHierarchy(), langSpec); + } + input = langSpec.newMethodDeclaration(inputMethodName, false, null, resInputParams); if (component != null) { // A component is created for this resource. component.addMethod(input); @@ -968,10 +1058,10 @@ } // Declare the accessor in the main component to call the input method. - String str = ((Term) message).getSymbol().getImplName(); - inputAccessor = getMethod(mainComponent, str); + String messageSymbol = ((Term) message).getSymbol().getImplName(); + inputAccessor = getMethod(mainComponent, messageSymbol); if (inputAccessor == null) { - inputAccessor = langSpec.newMethodDeclaration(str, false, null, mainInputParams); + inputAccessor = langSpec.newMethodDeclaration(messageSymbol, false, null, mainInputParams); mainComponent.addMethod(inputAccessor); } else { // Add type to a parameter without type. @@ -1017,10 +1107,14 @@ v++; } } + String inputMethodName = ((Variable) message).getName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += _for + getComponentName(out.getResource().getResourceHierarchy(), langSpec); + } if (resInputParams.size() == 0) { - input = langSpec.newMethodDeclaration(((Variable) message).getName(), null); + input = langSpec.newMethodDeclaration(inputMethodName, null); } else { - input = langSpec.newMethodDeclaration(((Variable) message).getName(), false, null, resInputParams); + input = langSpec.newMethodDeclaration(inputMethodName, false, null, resInputParams); } if (component != null) { // A component is created for this resource. @@ -1031,13 +1125,13 @@ } // Declare the accessor in the main component to call the input method. - String str = ((Variable) message).getName(); - inputAccessor = getMethod(mainComponent, str); + String messageSymbol = ((Variable) message).getName(); + inputAccessor = getMethod(mainComponent, messageSymbol); if (inputAccessor == null) { if (mainInputParams.size() == 0) { - inputAccessor = langSpec.newMethodDeclaration(str, null); + inputAccessor = langSpec.newMethodDeclaration(messageSymbol, null); } else { - inputAccessor = langSpec.newMethodDeclaration(str, false, null, mainInputParams); + inputAccessor = langSpec.newMethodDeclaration(messageSymbol, false, null, mainInputParams); } mainComponent.addMethod(inputAccessor); } @@ -1115,34 +1209,34 @@ } input.addFirstStatement(updateStatement); } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - // ToDo. + String updateStatement = ""; + if (sideEffects[0] != null) { 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); - } + String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); + updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + } + 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 += 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 += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + if (updateStatement != null) { + input.addFirstStatement(updateStatement); } } } @@ -1199,9 +1293,26 @@ params.add(refVarName); } } - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) chToRes.getDestination()).getResourceName()), - updateMethodName + resComponentName, - params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); + if (!generatesComponent(srcRes)) { + srcRes = srcRes.getParent(); + } + String updateMethodName = null; + ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + if (!generatesComponent(dstRes)) { + updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; + dstRes = dstRes.getParent(); + } else { + updateMethodName = updateMethodPrefix + from + resComponentName; + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (srcRes != dstRes) { + input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, params) + + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + } else { + input.addStatement(langSpec.getMethodInvocation(updateMethodName, params) + + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); + } } } if (outsideInputMembers2.size() > 0) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 7d62432..70f6cd0 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -28,8 +28,9 @@ boolean declareField(); String getFieldAccessor(String fieldName); String getMethodInvocation(String methodName); - String getMethodInvocation(String receivertName, String methodName); - String getMethodInvocation(String receivertName, String methodName, List parameters); + String getMethodInvocation(String receiverName, List parameters); + String getMethodInvocation(String receiverName, String methodName); + String getMethodInvocation(String receiverName, String methodName, List parameters); String getConstructorInvocation(String componentName, List parameters); String getReturnStatement(String returnValue); String toComponentName(String name); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 76971ed..871630a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -129,7 +129,8 @@ Map resourceComponents = new HashMap<>(); Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); - List> inputs = new ArrayList<>(); + Map> updates = new HashMap<>(); + Map> inputs = new HashMap<>(); List> fields = new ArrayList<>(); List> constructorParams = new ArrayList<>(); @@ -145,28 +146,28 @@ mainComponent.addMethod(mainConstructor); // For each resource node. - for (ResourceNode rn: resources) { + for (ResourceNode resourceNode: resources) { TypeDeclaration component = null; - if (generatesComponent(rn.getResourceHierarchy())) { + Set depends = new HashSet<>(); + Set refs = new HashSet<>(); + if (generatesComponent(resourceNode.getResourceHierarchy())) { boolean f = false; - String resourceName = getComponentName(rn.getResourceHierarchy()); + String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - component = resourceComponents.get(rn.getResourceHierarchy()); + component = resourceComponents.get(resourceNode.getResourceHierarchy()); if (component == null) { // Add compilation unit for each resource. component = new TypeDeclaration(resourceName); - resourceComponents.put(rn.getResourceHierarchy(), component); + resourceComponents.put(resourceNode.getResourceHierarchy(), component); CompilationUnit cu = new CompilationUnit(component); cu.addImport(new ImportDeclaration("java.util.*")); codes.add(cu); // Declare the field to refer to each resource in the main type. - Set depends = new HashSet<>(); - Set refs = new HashSet<>(); - if (rn.getResourceHierarchy().getParent() == null) { + if (resourceNode.getResourceHierarchy().getParent() == null) { // For a root resource String fieldInitializer = "new " + resourceName + "("; - for (Edge resToCh: rn.getOutEdges()) { + for (Edge resToCh: resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { for (Edge chToRes: re.getDestination().getOutEdges()) { @@ -178,7 +179,7 @@ } } } - for (Edge chToRes : rn.getInEdges()) { + for (Edge chToRes : resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); @@ -201,7 +202,7 @@ } for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { - if (rn.getResourceHierarchy().equals(dependingRes)) { + if (resourceNode.getResourceHierarchy().equals(dependingRes)) { // Declare a field to refer to outside resources. depends.add(dependedRes); String resName = getComponentName(dependedRes); @@ -212,7 +213,7 @@ } for (Channel ch : model.getChannels()) { DataTransferChannel c = (DataTransferChannel) ch; - if (c.getInputResources().contains(rn.getOutSideResource())) { + if (c.getInputResources().contains(resourceNode.getOutSideResource())) { for (ResourcePath res: c.getReferenceResources()) { if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { refs.add(res); @@ -225,225 +226,92 @@ } if (f) fieldInitializer = fieldInitializer.substring(0, fieldInitializer.length() - 1); fieldInitializer += ")"; - FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), rn.getResourceName()); + FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), resourceNode.getResourceName()); mainComponent.addField(field); Block mainConstructorBody = mainConstructor.getBody(); if (mainConstructorBody == null) { mainConstructorBody = new Block(); mainConstructor.setBody(mainConstructorBody); } - mainConstructorBody.addStatement(rn.getResourceName() + " = " + fieldInitializer + ";"); + mainConstructorBody.addStatement(resourceNode.getResourceName() + " = " + fieldInitializer + ";"); } - // Declare a constructor, fields and update methods in the type of each resource. - MethodDeclaration constructor = new MethodDeclaration(resourceName, true); - Block block = new Block(); - depends = new HashSet<>(); - for (Edge resToCh : rn.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.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(rn.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(rn.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { - // Declare a field to refer to the destination resource of push transfer. - for (Edge chToRes: re.getDestination().getOutEdges()) { - ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); - if (!generatesComponent(dstRes.getResourceHierarchy())) { - dstRes = dstRes.getParent(); - } - String dstResName = getComponentName(dstRes.getResourceHierarchy()); - depends.add(dstRes.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); - constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); - block.addStatement("this." + toVariableName(dstResName) + " = " + toVariableName(dstResName) + ";"); - if (outsideOutputResource) { - if (dstRes.getParent() != null) { - // Reference to root resource. - ResourcePath dstRootRes = dstRes.getRoot(); - String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName))); - constructor.addParameter(new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName))); - block.addStatement("this." + toVariableName(dstRootResName) + " = " + toVariableName(dstRootResName) + ";"); - } - } - } - } - } - for (Edge chToRes : rn.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 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; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(rn.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - String srcResName = null; - ResourcePath srcRes2 = srcRes; - if (generatesComponent(srcRes.getResourceHierarchy())) { - srcResName = getComponentName(srcRes.getResourceHierarchy()); - } else { - srcRes2 = srcRes.getParent(); - srcResName = getComponentName(srcRes2.getResourceHierarchy()); - } - if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - // Declare a field to refer to the source resource of pull transfer. - depends.add(srcRes2.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); - constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); - block.addStatement("this." + toVariableName(srcResName) + " = " + toVariableName(srcResName) + ";"); - if (outsideInputResource) { - if (srcRes2.getParent() != null) { - // Reference to root resource. - ResourcePath srcRootRes = srcRes2.getRoot(); - String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName))); - constructor.addParameter(new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName))); - block.addStatement("this." + toVariableName(srcRootResName) + " = " + toVariableName(srcRootResName) + ";"); - } - } - } else { - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); - DataTransferChannel c = ((ChannelNode) resToCh.getDestination()).getChannel(); - for (ResourcePath ref: c.getReferenceResources()) { - if (!ref.equals(rn.getOutSideResource())) { - vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); - } - } - component.addMethod(new MethodDeclaration("update" + srcResName, false, typeVoid, vars)); - } - } - } - // Declare a field to refer to outside resources. - if (rn.getParent() == null) { - for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { - for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { - if (rn.getResourceHierarchy().equals(dependingRes)) { - // Declare a field to refer to outside resources. - depends.add(dependedRes); - String resName = getComponentName(dependedRes); - component.addField(new FieldDeclaration(new Type(resName, resName), toVariableName(resName))); - constructor.addParameter(new VariableDeclaration(new Type(resName, resName), toVariableName(resName))); - block.addStatement("this." + toVariableName(resName) + " = " + toVariableName(resName) + ";"); - } - } - } - } - // Declare a field to refer to the reference resource. - refs = new HashSet<>(); - for (Channel ch : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) ch; - if (c.getInputResources().contains(rn.getOutSideResource())) { - for (ResourcePath res: c.getReferenceResources()) { - if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { - refs.add(res); - String refResName = getComponentName(res.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(refResName, refResName), res.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(refResName, refResName), res.getResourceName())); - block.addStatement("this." + res.getResourceName() + " = " + res.getResourceName() + ";"); - } - } - } - } - constructor.setBody(block); - if (constructor.getParameters() != null) { - component.addMethod(constructor); - resourceConstructors.put(rn.getResourceHierarchy(), constructor); - } - } - - // Declare the field to store the state in the type of each resource. - if (((StoreAttribute) rn.getAttribute()).isStored()) { - ResourcePath res = rn.getOutSideResource(); - Set children = rn.getResourceHierarchy().getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - Type fieldType = getImplStateType(res.getResourceHierarchy()); - component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); - constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getResourceHierarchy(), new VariableDeclaration(fieldType, toVariableName(resourceName)))); - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - component.addField(new FieldDeclaration(getImplStateType(res.getResourceHierarchy()), "value", getInitializer(res))); + // Declare the field to store the state in the type of each resource. + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + ResourcePath res = resourceNode.getOutSideResource(); + Set children = resourceNode.getResourceHierarchy().getChildren(); + if (children == null || children.size() == 0) { + // leaf resource. + Type fieldType = getImplStateType(res.getResourceHierarchy()); + component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), new VariableDeclaration(fieldType, toVariableName(resourceName)))); } else { - // class - for (ResourceHierarchy c: children) { - String childTypeName = getComponentName(c); - Type childType = null; - if (generatesComponent(c)) { - // The child has a component. - childType = new Type(childTypeName, childTypeName); - String fieldName = toVariableName(childTypeName); - component.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); + ResourceHierarchy child = children.iterator().next(); + if (children.size() == 1 && child.getNumParameters() > 0) { + // map or list. + component.addField(new FieldDeclaration(getImplStateType(res.getResourceHierarchy()), "value", getInitializer(res))); + } else { + // class + for (ResourceHierarchy c: children) { + String childTypeName = getComponentName(c); + Type childType = null; + if (generatesComponent(c)) { + // The child has a component. + childType = new Type(childTypeName, childTypeName); + String fieldName = toVariableName(childTypeName); + component.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); + } } } } } - } - - // Declare the getter methods to obtain the children resources. - for (ResourceNode child: rn.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // A component for the child is generated. - List params = new ArrayList<>(); - int v = 1; - for (Selector param: child.getSelectors()) { - if (param.getExpression() instanceof Variable) { - Variable var = (Variable) param.getExpression(); - params.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param.getExpression() instanceof Term) { - Term var = (Term) param.getExpression(); - params.add(new VariableDeclaration(var.getType(), "v" + v)); + + // Declare the getter method to obtain the resource state in this component. + MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(resourceNode.getResourceHierarchy())); + component.addMethod(stateGetter); + + // Declare the accessor method in the main type to call the getter method. + declareAccessorMethodInMainComponent(resourceNode, mainComponent); + + // Declare the getter methods to obtain the children resources. + Set children = new HashSet<>(); + for (ResourceNode child: resourceNode.getChildren()) { + if (generatesComponent(child.getResourceHierarchy())) { + // A component for the child is generated. + if (!children.contains(child.getResourceHierarchy())) { + children.add(child.getResourceHierarchy()); + List params = new ArrayList<>(); + int v = 1; + for (Selector param: child.getSelectors()) { + if (param.getExpression() instanceof Variable) { + Variable var = (Variable) param.getExpression(); + params.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (param.getExpression() instanceof Term) { + Term var = (Term) param.getExpression(); + params.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + String childCompName = getComponentName(child.getResourceHierarchy()); + Type childType = new Type(childCompName, childCompName); + MethodDeclaration childGetter = null; + if (params.size() == 0) { + childGetter = new MethodDeclaration("get" + childCompName, childType); + } else { + childGetter = new MethodDeclaration("get" + childCompName, false, childType, params); + } + component.addMethod(childGetter); } - v++; } - String childCompName = getComponentName(child.getResourceHierarchy()); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (params.size() == 0) { - childGetter = new MethodDeclaration("get" + childCompName, childType); - } else { - childGetter = new MethodDeclaration("get" + childCompName, false, childType, params); - } - component.addMethod(childGetter); } - } + } } // Declare the state field and reference fields in the parent component. if (component == null) { // Declare reference fields for push/pull data transfer. boolean noPullTransfer = true; - for (Edge resToCh : rn.getOutEdges()) { + for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); for (Edge chToRes: re.getDestination().getOutEdges()) { @@ -462,20 +330,20 @@ } String dstResName = getComponentName(dstRes.getResourceHierarchy()); FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPush)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); if (dstRes.getParent() != null) { // Reference to root resource. ResourcePath dstRootRes = dstRes.getRoot(); String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); Type dstRootResType = new Type(dstRootResName, dstRootResName); FieldDeclaration refRootFieldForPush = new FieldDeclaration(dstRootResType, toVariableName(dstRootResName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refRootFieldForPush)); - constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(dstRootResType, toVariableName(dstRootResName)))); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPush)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(dstRootResType, toVariableName(dstRootResName)))); } } } } - for (Edge chToRes : rn.getInEdges()) { + for (Edge chToRes : resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); @@ -494,98 +362,276 @@ } String srcResName = getComponentName(srcRes.getResourceHierarchy()); FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPull)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); if (srcRes.getParent() != null) { // Reference to root resource. ResourcePath srcRootRes = srcRes.getRoot(); String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); Type srcRootResType = new Type(srcRootResName, srcRootResName); FieldDeclaration refRootFieldForPull = new FieldDeclaration(srcRootResType, toVariableName(srcRootResName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refRootFieldForPull)); - constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(srcRootResType, toVariableName(srcRootResName)))); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPull)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(srcRootResType, toVariableName(srcRootResName)))); } noPullTransfer = false; } } } // Declare the state field in the parent component. - ResourceHierarchy res = rn.getOutSideResource().getResourceHierarchy(); - if (((StoreAttribute) rn.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { + ResourceHierarchy res = resourceNode.getOutSideResource().getResourceHierarchy(); + if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { String resName = getComponentName(res); FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName)))); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName)))); } } - // Declare the getter method in this component to obtain the resource state. - if (component != null) { - // A component is created for this resource. - MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(rn.getResourceHierarchy())); - component.addMethod(stateGetter); - } else { - // No component is created for this resource. - List getterParams = new ArrayList<>(); - int v = 1; - for (Selector param: rn.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)); + // Declare the getter method to obtain the resource state in the parent component. + if (component == null) { + // No component is created for this resource. + String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy()); + boolean bExists = false; + for (Map.Entry entry: getters) { + if (entry.getKey() == resourceNode.getParent().getResourceHierarchy() && entry.getValue().getName().equals(getterName)) { + bExists = true; + break; } - v++; } - String resCompName = getComponentName(rn.getResourceHierarchy()); - Type resType = getImplStateType(rn.getResourceHierarchy()); - MethodDeclaration stateGetter = null; - if (getterParams.size() == 0) { - stateGetter = new MethodDeclaration("get" + resCompName, resType); - } else { - stateGetter = new MethodDeclaration("get" + resCompName, false, resType, getterParams); + if (!bExists) { + List 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++; + } + Type resType = getImplStateType(resourceNode.getResourceHierarchy()); + MethodDeclaration stateGetter = null; + if (getterParams.size() == 0) { + stateGetter = new MethodDeclaration(getterName, resType); + } else { + stateGetter = new MethodDeclaration(getterName, false, resType, getterParams); + } + getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateGetter)); + + // Declare the accessor method in the main type to call the getter method. + declareAccessorMethodInMainComponent(resourceNode, mainComponent); } - getters.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateGetter)); } - // Declare the accessor method in the main type to call the getter method. - MethodDeclaration accessor = null; - List mainGetterParams = new ArrayList<>(); - int v = 1; - for (Selector param: rn.getAllSelectors()) { - if (param.getExpression() instanceof Variable) { - Variable var = (Variable) param.getExpression(); - mainGetterParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param.getExpression() instanceof Term) { - Term var = (Term) param.getExpression(); - mainGetterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + // Declare fields and update methods in the type of each resource. + for (Edge resToCh : resourceNode.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + DataTransferChannel ch = ((ChannelNode) re.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; + } } - v++; + // 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) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { + // Declare a field to refer to the destination resource of push transfer. + for (Edge chToRes: re.getDestination().getOutEdges()) { + ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); + } + String dstResName = getComponentName(dstRes.getResourceHierarchy()); + depends.add(dstRes.getResourceHierarchy()); + FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + VariableDeclaration dstRefVar = new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + if (component != null) { + // A component is created for this resource. + component.addField(dstRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefVar)); + } + if (outsideOutputResource) { + if (dstRes.getParent() != null) { + // Reference to root resource. + ResourcePath dstRootRes = dstRes.getRoot(); + String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); + FieldDeclaration dstRootRefField = new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); + VariableDeclaration dstRootRefVar = new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); + if (component != null) { + // A component is created for this resource. + component.addField(dstRootRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRootRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefVar)); + } + } + } + } + } } - if (mainGetterParams.size() > 0) { - accessor = new MethodDeclaration("get" + getComponentName(rn.getResourceHierarchy()), - false, - getImplStateType(rn.getResourceHierarchy()), - mainGetterParams); - } else { - accessor = new MethodDeclaration("get" + getComponentName(rn.getResourceHierarchy()), - getImplStateType(rn.getResourceHierarchy())); + 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 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; + } + } + // 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; + } + } + String srcResName = getComponentName(srcRes.getResourceHierarchy()); + ResourcePath srcRes2 = srcRes; + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes2 = srcRes.getParent(); + } + if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { + // Declare a field to refer to the source resource of pull transfer. + depends.add(srcRes2.getResourceHierarchy()); + FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + VariableDeclaration srcRefVar = new VariableDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + if (component != null) { + // A component is created for this resource. + component.addField(srcRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefVar)); + } + if (outsideInputResource) { + if (srcRes2.getParent() != null) { + // Reference to root resource. + ResourcePath srcRootRes = srcRes2.getRoot(); + String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); + FieldDeclaration srcRootRefField = new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); + VariableDeclaration srcRootRefVar = new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); + if (component != null) { + // A component is created for this resource. + component.addField(srcRootRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRootRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefVar)); + } + } + } + } else { + // Declare an update method in the type of the destination resource. + ArrayList vars = new ArrayList<>(); + vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); + DataTransferChannel c = ((ChannelNode) resToCh.getDestination()).getChannel(); + for (ResourcePath ref: c.getReferenceResources()) { + if (!ref.equals(resourceNode.getOutSideResource())) { + vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); + } + } + MethodDeclaration update = null; + if (component != null) { + // A component is created for this resource. + update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, vars); + component.addMethod(update); + } else { + // No component is created for this resource. + String resourceName = getComponentName(resourceNode.getResourceHierarchy()); + String updateMethodName = "update" + resourceName + "From" + srcResName; + Map nameToMethod = updates.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + updates.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); + } + if (nameToMethod.get(updateMethodName) == null) { + update = new MethodDeclaration(updateMethodName, false, typeVoid, vars); + nameToMethod.put(updateMethodName, update); + } + } + } + } } - accessor.setBody(new Block()); - Expression getState = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(rn.getOutSideResource(), null); - accessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); - mainComponent.addMethod(accessor); - + // 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); + String resName = getComponentName(dependedRes); + FieldDeclaration refField = new FieldDeclaration(new Type(resName, resName), toVariableName(resName)); + VariableDeclaration refVar = new VariableDeclaration(new Type(resName, resName), toVariableName(resName)); + if (component != null) { + // A component is created for this resource. + component.addField(refField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refVar)); + } + } + } + } + } + // Declare a field to refer to the reference resource. + for (Channel ch : model.getChannels()) { + DataTransferChannel c = (DataTransferChannel) ch; + if (c.getInputResources().contains(resourceNode.getOutSideResource())) { + for (ResourcePath res: c.getReferenceResources()) { + if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { + refs.add(res); + String refResName = getComponentName(res.getResourceHierarchy()); + FieldDeclaration refResField = new FieldDeclaration(new Type(refResName, refResName), res.getResourceName()); + VariableDeclaration refResVar = new VariableDeclaration(new Type(refResName, refResName), res.getResourceName()); + if (component != null) { + // A component is created for this resource. + component.addField(refResField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refResVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResVar)); + } + } + } + } + } + // Declare the input method in this component and the main component. for (Channel ch : model.getIOChannels()) { for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { - if (rn.getInSideResources().contains(cm.getResource())) { + if (resourceNode.getInSideResources().contains(cm.getResource())) { Expression message = cm.getStateTransition().getMessageExpression(); if (message instanceof Term) { // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); - v = 1; + int v = 1; if (cm.getResource().getLastParam() != null) { Expression param = cm.getResource().getLastParam(); if (param instanceof Variable) { @@ -629,25 +675,43 @@ } else { // var has not come from a reference resource. resInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); + boolean bExists = false; + for (VariableDeclaration mainParam: mainInputParams) { + if (mainParam.getName().equals(var.getName()) ) { + bExists = true; + break; + } + } + if (!bExists) { + mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); + } } } - MethodDeclaration input = new MethodDeclaration( - ((Term) cm.getStateTransition().getMessageExpression()).getSymbol().getImplName(), - false, typeVoid, resInputParams); + String inputMethodName = ((Term) message).getSymbol().getImplName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); + } + MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams); if (component != null) { // A component is created for this resource. component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); + Map nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); + } + if (nameToMethod.get(inputMethodName) == null) { + nameToMethod.put(inputMethodName, input); + } } // In the main type. - String str = ((Term) cm.getStateTransition().getMessageExpression()).getSymbol().getImplName(); - input = getMethod(mainComponent, str, mainInputParams); + String messageSymbol = ((Term) message).getSymbol().getImplName(); + input = getMethod(mainComponent, messageSymbol, mainInputParams); if (input == null) { - input = new MethodDeclaration(str, false, typeVoid, mainInputParams); + input = new MethodDeclaration(messageSymbol, false, typeVoid, mainInputParams); mainComponent.addMethod(input); } else { // Add type to a parameter without type. @@ -665,7 +729,7 @@ // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); - v = 1; + int v = 1; if (cm.getResource().getLastParam() != null) { Expression param = cm.getResource().getLastParam(); if (param instanceof Variable) { @@ -691,32 +755,39 @@ v++; } } + String inputMethodName = ((Variable) message).getName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); + } MethodDeclaration input = null; if (resInputParams.size() > 0) { - input = new MethodDeclaration( - ((Variable) cm.getStateTransition().getMessageExpression()).getName(), - false, typeVoid, resInputParams); + input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams); } else { - input = new MethodDeclaration( - ((Variable) cm.getStateTransition().getMessageExpression()).getName(), - false, typeVoid, null); + input = new MethodDeclaration(inputMethodName, false, typeVoid, null); } if (component != null) { // A component is created for this resource. component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); + Map nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); + } + if (nameToMethod.get(inputMethodName) == null) { + nameToMethod.put(inputMethodName, input); + } } // In the main type. - String str = ((Variable) cm.getStateTransition().getMessageExpression()).getName(); - input = getMethod(mainComponent, str, mainInputParams); + String messageSymbol = ((Variable) message).getName(); + input = getMethod(mainComponent, messageSymbol, mainInputParams); if (input == null) { if (mainInputParams.size() > 0) { - input = new MethodDeclaration(str, false, typeVoid, mainInputParams); + input = new MethodDeclaration(messageSymbol, false, typeVoid, mainInputParams); } else { - input = new MethodDeclaration(str, false, typeVoid, null); + input = new MethodDeclaration(messageSymbol, false, typeVoid, null); } mainComponent.addMethod(input); } @@ -731,9 +802,18 @@ resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); } + // Add leaf update methods to the parent components. + for (Map.Entry> entry: updates.entrySet()) { + for (MethodDeclaration update: entry.getValue().values()) { + resourceComponents.get(entry.getKey()).addMethod(update); + } + } + // Add leaf input methods to the parent components. - for (Map.Entry entry: inputs) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); + for (Map.Entry> entry: inputs.entrySet()) { + for (MethodDeclaration input: entry.getValue().values()) { + resourceComponents.get(entry.getKey()).addMethod(input); + } } // Add leaf reference fields to the parent components. @@ -892,6 +972,35 @@ orderedList.add(0, curResNode); } + private static void declareAccessorMethodInMainComponent(ResourceNode resourceNode, TypeDeclaration mainComponent) { + MethodDeclaration getterAccessor = null; + List mainGetterParams = new ArrayList<>(); + int v = 1; + for (Selector param: resourceNode.getAllSelectors()) { + if (param.getExpression() instanceof Variable) { + Variable var = (Variable) param.getExpression(); + mainGetterParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (param.getExpression() instanceof Term) { + Term var = (Term) param.getExpression(); + mainGetterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + if (mainGetterParams.size() > 0) { + getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), + false, + getImplStateType(resourceNode.getResourceHierarchy()), + mainGetterParams); + } else { + getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), + getImplStateType(resourceNode.getResourceHierarchy())); + } + getterAccessor.setBody(new Block()); + Expression getState = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(resourceNode.getOutSideResource(), null); + getterAccessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); + mainComponent.addMethod(getterAccessor); + } + private static List addConstructorParameters(ResourceHierarchy resource, Map resourceComponents, Map resourceConstructors, diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 443d7bf..3d51562 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -89,17 +89,14 @@ } if (pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { // for push data transfer - String srcResName = null; - if (srcComponent == null) { - srcResName = srcResourceName; - } else { - srcResName = srcComponent.getTypeName(); - } + MethodDeclaration update = null; if (dstComponent == null) { String dstParentResourceName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); dstComponent = componentMap.get(dstParentResourceName); + update = getUpdateMethod(dstComponent, dstResourceName, srcResourceName); + } else { + update = getUpdateMethod(dstComponent, null, srcResourceName); } - MethodDeclaration update = getUpdateMethod(dstComponent, srcResName); if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst side resource (when every incoming edge is in push style) Expression updateExp = null; @@ -129,15 +126,45 @@ } // Add statements to the update method. String[] sideEffects = new String[] {""}; - String curState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; + String newState = updateExp.toImplementation(sideEffects); + if (JavaCodeGenerator.generatesComponent(outRes)) { + String updateStatement; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + } else { + updateStatement = sideEffects[0] + "this.value = " + newState + ";"; + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + update.addFirstStatement(updateStatement); + } } else { - updateStatement = sideEffects[0] + "this.value = " + curState + ";"; - } - if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { - update.addFirstStatement(updateStatement); + String updateStatement = ""; + if (sideEffects[0] != null) { + updateStatement = sideEffects[0]; + updateStatement = updateStatement.replace(".value", "." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes))); + } + if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + update.addFirstStatement(updateStatement); + } } } if (resToCh.getDestination().getIndegree() > 1 @@ -192,7 +219,13 @@ break; } } - for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent)) { + String srcResName = null; + if (srcComponent == null) { + String srcParentResourceName = JavaCodeGenerator.getComponentName(src.getResourceHierarchy().getParent()); + srcComponent = componentMap.get(srcParentResourceName); + srcResName = srcResourceName; + } + for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent, srcResName)) { String refParams = ""; Set referredSet = referredResources.get(srcUpdate); for (ChannelMember rc: ch.getReferenceChannelMembers()) { @@ -215,7 +248,17 @@ refParams += ", " + refVarName; } } - srcUpdate.addStatement("this." + dstResourceName + ".update" + srcComponent.getTypeName() + "(value" + refParams + ");"); + String updateMethodName = null; + if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { + updateMethodName = "updateFrom" + srcResourceName; + } else { + updateMethodName = "update" + dstResourceName + "From" + srcResourceName; + } + if (srcComponent != dstComponent) { + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(value" + refParams + ");"); + } else { + srcUpdate.addStatement("this." + updateMethodName + "(value" + refParams + ");"); + } } for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { String refParams = ""; @@ -240,7 +283,17 @@ refParams += ", " + refVarName; } } - srcInput.addStatement("this." + dstResourceName + ".update" + srcComponent.getTypeName() + "(value" + refParams + ");"); + String updateMethodName = null; + if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { + updateMethodName = "updateFrom" + srcResourceName; + } else { + updateMethodName = "update" + dstResourceName + "From" + srcResourceName; + } + if (srcComponent != dstComponent) { + srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(value" + refParams + ");"); + } else { + srcInput.addStatement("this." + updateMethodName + "(value" + refParams + ");"); + } } } else if ((pushPull.getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // for pull (or push/pull) data transfer @@ -341,7 +394,8 @@ DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); if (ch2.getInputChannelMembers().size() == 0) { // In an input method of the parent component. - MethodDeclaration input = getInputMethod(dependingComponent, ch2.getOutputChannelMembers().iterator().next()); + Set outs = ch2.getOutputChannelMembers(); + MethodDeclaration input = getInputMethod(dependingComponent, outs.iterator().next(), outs.size()); String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); input.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. @@ -362,7 +416,13 @@ for (Edge resToCh2: chToRes2.getSource().getInEdges()) { // In an update method of the parent component. ResourceNode dependingResSrc = (ResourceNode) resToCh2.getSource(); - MethodDeclaration update = getUpdateMethod(dependingComponent, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); + MethodDeclaration update = null; + if (JavaCodeGenerator.generatesComponent(dependingRes.getResourceHierarchy())) { + update = getUpdateMethod(dependingComponent, null, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); + } else { + String dependingResName = JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy()); + update = getUpdateMethod(dependingComponent, dependingResName, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); + } update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. } // Update constructor. @@ -375,7 +435,13 @@ } else { if (pushPull2.getOptions().get(0) == PushPullValue.PUSH) { // In an update method of the destination component. - MethodDeclaration update = getUpdateMethod(dstComponent, JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy())); + MethodDeclaration update = null; + if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { + update = getUpdateMethod(dstComponent, null, JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy())); + } else { + String dstResName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy()); + update = getUpdateMethod(dstComponent, dstResName, JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy())); + } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. @@ -498,13 +564,13 @@ MethodDeclaration input = null; if (JavaCodeGenerator.generatesComponent(resource)) { // A component is generated for this resource. - input = getInputMethod(component, out); + input = getInputMethod(component, out, entry.getKey().getOutputChannelMembers().size()); } else { // No component is generated for this resource. ResourceHierarchy parent = resource.getParent(); if (parent != null) { TypeDeclaration parentType = componentMap.get(JavaCodeGenerator.getComponentName(parent)); - input = getInputMethod(parentType, out); + input = getInputMethod(parentType, out, entry.getKey().getOutputChannelMembers().size()); } } if (input != null) { @@ -535,39 +601,45 @@ input.addFirstStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - // ToDo. + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; - } else { - if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - 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(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - 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 { - updateStatement = sideEffects[0] + "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; - } - if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { - input.addFirstStatement(updateStatement); - } + updateStatement = updateStatement.replace(".value", "." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource))); + } + if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + 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 += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + 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 += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; + } + if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { + input.addFirstStatement(updateStatement); } } // In the main type if (mainComponent != null) { - MethodDeclaration inputAccessor = getMethod(mainComponent, input.getName()); + Expression message = out.getStateTransition().getMessageExpression(); + String inputAccessorName = input.getName(); + if (message instanceof Term) { + inputAccessorName = ((Term) message).getSymbol().getImplName(); + } else if (message instanceof Variable) { + inputAccessorName = ((Variable) message).getName(); + } + MethodDeclaration inputAccessor = getMethod(mainComponent, inputAccessorName); if (inputAccessor != null) { Set referredSet = referredResources.get(input); for (ChannelMember rc: entry.getKey().getReferenceChannelMembers()) { @@ -601,8 +673,7 @@ resExp = ((Term) resExp).getChild(0); } String resourceAccess = resExp.toImplementation(new String[] {null}); - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); + if (message instanceof Term) { for (Map.Entry varEnt: message.getVariables().entrySet()) { String refVarName = null; for (ChannelMember rc: entry.getKey().getReferenceChannelMembers()) { @@ -671,18 +742,28 @@ return null; } - private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String fromResName) { + private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String dstResName, String srcResName) { for (MethodDeclaration m: component.getMethods()) { - if (m.getName().equals("update" + fromResName)) return m; + if (dstResName == null) { + if (m.getName().equals("updateFrom" + srcResName)) return m; + } else { + if (m.getName().equals("update" + dstResName + "From" + srcResName)) return m; + } } return null; } - private static List getUpdateMethods(TypeDeclaration component) { + private static List getUpdateMethods(TypeDeclaration component, String resName) { List updates = new ArrayList<>(); for (MethodDeclaration m: component.getMethods()) { - if (m.getName().startsWith("update")) { - updates.add(m); + if (resName == null) { + if (m.getName().startsWith("updateFrom")) { + updates.add(m); + } + } else { + if (m.getName().startsWith("update" + resName + "From")) { + updates.add(m); + } } } return updates; @@ -723,7 +804,7 @@ // I/O channel for (ChannelMember out: channel.getOutputChannelMembers()) { if (resource.getInSideResources().contains(out.getResource())) { - MethodDeclaration input = getInputMethod(component, out); + MethodDeclaration input = getInputMethod(component, out, channel.getOutputChannelMembers().size()); inputs.add(input); } } @@ -738,7 +819,7 @@ // I/O channel for (ChannelMember out: channel.getOutputChannelMembers()) { if (resource.equals(out.getResource().getResourceHierarchy())) { - MethodDeclaration input = getInputMethod(component, out); + MethodDeclaration input = getInputMethod(component, out, channel.getOutputChannelMembers().size()); inputs.add(input); } } @@ -746,15 +827,19 @@ return inputs; } - private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember cm) { - MethodDeclaration input = null; + private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember cm, int outNumber) { + String inputMethodName = null; if (cm.getStateTransition().getMessageExpression() instanceof Term) { Term message = (Term) cm.getStateTransition().getMessageExpression(); - input = getMethod(component, message.getSymbol().getImplName()); + inputMethodName =message.getSymbol().getImplName(); } else if (cm.getStateTransition().getMessageExpression() instanceof Variable) { Variable message = (Variable) cm.getStateTransition().getMessageExpression(); - input = getMethod(component, message.getName()); + inputMethodName = message.getName(); } + if (outNumber > 1) { + inputMethodName += "For" + JavaCodeGenerator.getComponentName(cm.getResource().getResourceHierarchy()); + } + MethodDeclaration input = getMethod(component, inputMethodName); return input; } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index 62743b9..662834a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -131,6 +131,23 @@ } @Override + public String getMethodInvocation(String methodName, List parameters) { + if (parameters == null) return getMethodInvocation( methodName); + String invocation = self + "." + methodName + "("; + if (parameters.size() > 0) { + for (int i = 0; i < parameters.size(); i++) { + if (i < parameters.size() - 1) { + invocation += parameters.get(i) + ", "; + } else { + invocation += parameters.get(i); + } + } + } + invocation += ")"; + return invocation; + } + + @Override public String getMethodInvocation(String receiverName, String methodName) { return receiverName + "." + methodName + "()"; } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index b791f97..26cb8c8 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -133,33 +133,35 @@ Map resourceComponents = new HashMap<>(); Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); - List> inputs = new ArrayList<>(); + Map> updates = new HashMap<>(); + Map> inputs = new HashMap<>(); List> fields = new ArrayList<>(); Map getterAccessors = new HashMap<>(); Map inputAccessors = new HashMap<>(); - List> constructorParams = new ArrayList<>(); + Map> constructorParams = new HashMap<>(); + Map priorMemberForInputChannel = new HashMap<>(); // For each resource node. for (Node n : resources) { - ResourceNode rn = (ResourceNode) n; + ResourceNode resourceNode = (ResourceNode) n; TypeDeclaration component = null; - if (generatesComponent(rn.getResourceHierarchy())) { - String resourceName = getComponentName(rn.getResourceHierarchy()); + if (generatesComponent(resourceNode.getResourceHierarchy())) { + String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - component = resourceComponents.get(rn.getResourceHierarchy()); + component = resourceComponents.get(resourceNode.getResourceHierarchy()); if (component == null) { // Add compilation unit for each resource. component = new TypeDeclaration(resourceName); - if (rn.getResourceHierarchy().getParent() == null) { + if (resourceNode.getResourceHierarchy().getParent() == null) { // For a root node. component.addAnnotation(new Annotation("Component")); - component.addAnnotation(new Annotation("Path", "\"/" + rn.getResourceName() + "\"")); + component.addAnnotation(new Annotation("Path", "\"/" + resourceNode.getResourceName() + "\"")); } - resourceComponents.put(rn.getResourceHierarchy(), component); + resourceComponents.put(resourceNode.getResourceHierarchy(), component); CompilationUnit cu = new CompilationUnit(component); cu.addImport(new ImportDeclaration("java.util.*")); - if (rn.getResourceHierarchy().getParent() == null) { + if (resourceNode.getResourceHierarchy().getParent() == null) { // For a root node. cu.addImport(new ImportDeclaration("javax.ws.rs.*")); cu.addImport(new ImportDeclaration("javax.ws.rs.client.*")); @@ -170,118 +172,81 @@ } codes.add(cu); - // Declare a client field and update methods from other resources. - boolean bDeclareClientField = false; - for (Edge resToCh: rn.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.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(rn.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; + // Declare the field to store the state in the type of each resource. + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + ResourcePath res = resourceNode.getOutSideResource(); + Set children = resourceNode.getResourceHierarchy().getChildren(); + if (children == null || children.size() == 0) { + // leaf resource. + Type fieldType = getImplStateType(res.getResourceHierarchy()); + component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); + Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); } - } - if (!bDeclareClientField && ((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { - for (ChannelMember cm: ch.getOutputChannelMembers()) { - ResourcePath dstRes = cm.getResource(); - String dstResName = null; - if (generatesComponent(dstRes.getResourceHierarchy())) { - dstResName = getComponentName(dstRes.getResourceHierarchy()); - } else { - dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); - } - if (rn.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { - // Inter-service - if (bDeclareClientField) { - // Declare a client field to connect to the destination resource of push transfer. - component.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; + String varName = toVariableName(resourceName); + if (nameToParam.get(varName) == null) { + nameToParam.put(varName, new VariableDeclaration(fieldType, varName)); + } + } else { + ResourceHierarchy child = children.iterator().next(); + if (children.size() == 1 && child.getNumParameters() > 0) { + // map or list. + component.addField(new FieldDeclaration(getImplStateType(res.getResourceHierarchy()), "value", getInitializer(res))); + } else { + // class + for (ResourceHierarchy c: children) { + String childTypeName = getComponentName(c); + Type childType = null; + if (generatesComponent(c)) { + // The child has a component. + childType = new Type(childTypeName, childTypeName); + String fieldName = toVariableName(childTypeName); + component.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); } - } else { - // Inner-service - // Declare a field to directly refer to the destination resource of push transfer. - component.addField(new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); } } } } - for (Edge chToRes : rn.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 input and output resources are 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; - } - } - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(rn.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - String srcResName = null; - if (generatesComponent(srcRes.getResourceHierarchy())) { - srcResName = getComponentName(srcRes.getResourceHierarchy()); - } else { - srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); - } - if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - if (rn.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { - // Inter-service - if (!bDeclareClientField) { - // Declare a client field to connect to the source resource of pull transfer. - component.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; + + // Declare the getter method to obtain the resource state in the component of each resource. + MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(resourceNode.getResourceHierarchy())); + if (resourceNode.getResourceHierarchy().getParent() == null) { + // Since this getter is also an accessor. + stateGetter.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); + stateGetter.addAnnotation(new Annotation("GET")); + } + component.addMethod(stateGetter); + + // Declare the getter methods to obtain the children resources. + Set children = new HashSet<>(); + for (ResourceNode child: resourceNode.getChildren()) { + if (generatesComponent(child.getResourceHierarchy())) { + // The child generates a component. + if (!children.contains(child.getResourceHierarchy())) { + children.add(child.getResourceHierarchy()); + List pathParams = new ArrayList<>(); + int v = 1; + for (Selector pathParam: child.getSelectors()) { + if (pathParam.getExpression() instanceof Variable) { + Variable var = (Variable) pathParam.getExpression(); + pathParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (pathParam.getExpression() instanceof Term) { + Term var = (Term) pathParam.getExpression(); + pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); } + v++; + } + String childCompName = getComponentName(child.getResourceHierarchy()); + Type childType = new Type(childCompName, childCompName); + MethodDeclaration childGetter = null; + if (pathParams.size() == 0) { + childGetter = new MethodDeclaration("get" + childCompName, childType); } else { - // Inner-service - // Declare a field to directly refer to the source resource of pull transfer. - component.addField(new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); + childGetter = new MethodDeclaration("get" + childCompName, false, childType, pathParams); } - } else { - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - String srcName = srcRes.getResourceName(); - Type srcType = srcRes.getResourceStateType(); - VariableDeclaration param = new VariableDeclaration(srcType, srcName); - param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - vars.add(param); - for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { - if (!refRes.equals(rn.getOutSideResource())) { - param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); - param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); - vars.add(param); - } - } - MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); - for (ChannelMember cm: ((ChannelNode) re.getDestination()).getChannel().getOutputChannelMembers()) { - if (rn.getInSideResources().contains(cm.getResource())) { - if (cm.getStateTransition().isRightUnary()) { - update.addAnnotation(new Annotation("PUT")); - } else { - update.addAnnotation(new Annotation("POST")); - } - } - } - if (re.getDestination().getIndegree() > 1 - || (re.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { - // Declare a field to cache the state of the source resource in the type of the destination resource. - ResourcePath cacheRes = ((ResourceNode) re.getSource()).getOutSideResource(); - component.addField(new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes))); - if (re.getDestination().getIndegree() > 1) { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); - } - } - component.addMethod(update); + component.addMethod(childGetter); } } } @@ -304,72 +269,14 @@ // if (bDeclareClientField) break; // } // } - - // Declare the field to store the state in the type of each resource. - if (((StoreAttribute) rn.getAttribute()).isStored()) { - ResourcePath res = rn.getOutSideResource(); - Set children = rn.getResourceHierarchy().getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - Type fieldType = getImplStateType(res.getResourceHierarchy()); - component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); - constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getResourceHierarchy(), new VariableDeclaration(fieldType, toVariableName(resourceName)))); - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - component.addField(new FieldDeclaration(getImplStateType(res.getResourceHierarchy()), "value", getInitializer(res))); - } else { - // class - for (ResourceHierarchy c: children) { - String childTypeName = getComponentName(c); - Type childType = null; - if (generatesComponent(c)) { - // The child has a component. - childType = new Type(childTypeName, childTypeName); - String fieldName = toVariableName(childTypeName); - component.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); - } - } - } - } - } - - // Declare the getter methods to obtain the children resources. - for (ResourceNode child: rn.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // The child generates a component. - List pathParams = new ArrayList<>(); - int v = 1; - for (Selector pathParam: child.getSelectors()) { - if (pathParam.getExpression() instanceof Variable) { - Variable var = (Variable) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (pathParam.getExpression() instanceof Term) { - Term var = (Term) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } - String childCompName = getComponentName(child.getResourceHierarchy()); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (pathParams.size() == 0) { - childGetter = new MethodDeclaration("get" + childCompName, childType); - } else { - childGetter = new MethodDeclaration("get" + childCompName, false, childType, pathParams); - } - component.addMethod(childGetter); - } - } } // Declare the state field and reference fields in the parent component. + boolean bDeclareClientField = false; if (component == null) { // Declare reference fields for push/pull data transfer. - boolean bDeclareClientField = false; boolean noPullTransfer = true; - for (Edge resToCh : rn.getOutEdges()) { + for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); for (Edge chToRes: re.getDestination().getOutEdges()) { @@ -389,24 +296,24 @@ } else { dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); } - if (rn.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { + if (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the destination resource of push transfer. FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), clientField)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); bDeclareClientField = true; } } else { // Inner-service // Declare a field to directly refer to the destination resource of push transfer. FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPush)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); } } } } - for (Edge chToRes : rn.getInEdges()) { + for (Edge chToRes : resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); @@ -426,115 +333,299 @@ } else { srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); } - if (rn.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { + if (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the source resource of pull transfer. FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), clientField)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); bDeclareClientField = true; } } else { // Inner-service // Declare a field to directly refer to the source resource of pull transfer. FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPull)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); noPullTransfer = false; } } } } // Declare the state field in the parent component. - ResourceHierarchy res = rn.getOutSideResource().getResourceHierarchy(); - if (((StoreAttribute) rn.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { + ResourceHierarchy res = resourceNode.getOutSideResource().getResourceHierarchy(); + if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { String resName = getComponentName(res); FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName)); - fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName)))); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateField)); + + + Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToParam == null) { + nameToParam = new HashMap<>(); + constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); + } + String varName = toVariableName(resName); + if (nameToParam.get(varName) == null) { + nameToParam.put(varName, new VariableDeclaration(res.getResourceStateType(), varName)); + } } } - // Declare the getter method to obtain the resource state in the component of each resource. - if (component != null) { - // A component is created for this resource. - MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(rn.getResourceHierarchy())); - if (rn.getResourceHierarchy().getParent() == null) { - // Since this getter is also an accessor. - stateGetter.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); - stateGetter.addAnnotation(new Annotation("GET")); - } - component.addMethod(stateGetter); - } else { + // Declare the getter method to obtain the resource state in the parent component. + if (component == null) { // No component is created for this resource. - List pathParams = new ArrayList<>(); - int v = 1; - for (Selector pathParam: rn.getSelectors()) { - if (pathParam.getExpression() instanceof Variable) { - Variable var = (Variable) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (pathParam.getExpression() instanceof Term) { - Term var = (Term) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); + String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy()); + boolean bExists = false; + for (Map.Entry entry: getters) { + if (entry.getKey() == resourceNode.getParent().getResourceHierarchy() && entry.getValue().getName().equals(getterName)) { + bExists = true; + break; } - v++; } - String resCompName = getComponentName(rn.getResourceHierarchy()); - Type resType = getImplStateType(rn.getResourceHierarchy()); - MethodDeclaration stateGetter = null; - if (pathParams.size() == 0) { - stateGetter = new MethodDeclaration("get" + resCompName, resType); - } else { - stateGetter = new MethodDeclaration("get" + resCompName, false, resType, pathParams); + if (!bExists) { + List pathParams = new ArrayList<>(); + int v = 1; + for (Selector pathParam: resourceNode.getSelectors()) { + if (pathParam.getExpression() instanceof Variable) { + Variable var = (Variable) pathParam.getExpression(); + pathParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (pathParam.getExpression() instanceof Term) { + Term var = (Term) pathParam.getExpression(); + pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } + Type resType = getImplStateType(resourceNode.getResourceHierarchy()); + MethodDeclaration stateGetter = null; + if (pathParams.size() == 0) { + stateGetter = new MethodDeclaration(getterName, resType); + } else { + stateGetter = new MethodDeclaration(getterName, false, resType, pathParams); + } + getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateGetter)); } - getters.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateGetter)); } // Declare the getter accessor in the root resource. - if (rn.getResourceHierarchy().getParent() != null) { + if (resourceNode.getResourceHierarchy().getParent() != null) { // For a non-root resource MethodDeclaration getterAccessor = null; List mainGetterParams = new ArrayList<>(); - String resourcePath = getGetterResourcePathAndPathParams(rn.getOutSideResource(), mainGetterParams); + String resourcePath = getGetterResourcePathAndPathParams(resourceNode.getOutSideResource(), mainGetterParams); if (resourcePath.indexOf('/') > 0) { - resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); } else { - resourcePath = "\"" + resourcePath + "\""; + resourcePath = ""; } if (mainGetterParams.size() > 0) { - getterAccessor = new MethodDeclaration("get" + getComponentName(rn.getResourceHierarchy()) + "Value", + getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()) + "Value", false, - getImplStateType(rn.getResourceHierarchy()), + getImplStateType(resourceNode.getResourceHierarchy()), mainGetterParams); } else { - getterAccessor = new MethodDeclaration("get" + getComponentName(rn.getResourceHierarchy()) + "Value", - getImplStateType(rn.getResourceHierarchy())); + getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()) + "Value", + getImplStateType(resourceNode.getResourceHierarchy())); } getterAccessor.setBody(new Block()); - Expression getState = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(rn.getOutSideResource(), rn.getOutSideResource().getRoot()); + Expression getState = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(resourceNode.getOutSideResource(), resourceNode.getOutSideResource().getRoot()); getterAccessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); getterAccessor.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); getterAccessor.addAnnotation(new Annotation("GET")); - if (rn.getAllSelectors().size() > 0) { - getterAccessor.addAnnotation(new Annotation("Path", resourcePath)); + if (resourcePath.length() > 0) { + getterAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); } - getterAccessors.put(rn.getResourceHierarchy(), getterAccessor); + getterAccessors.put(resourceNode.getResourceHierarchy(), getterAccessor); + } + + // Declare a client field and update methods from other resources. + for (Edge resToCh: resourceNode.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + DataTransferChannel ch = ((ChannelNode) re.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; + } + } + if (!bDeclareClientField && ((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { + for (ChannelMember cm: ch.getOutputChannelMembers()) { + ResourcePath dstRes = cm.getResource(); + String dstResName = null; + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstResName = getComponentName(dstRes.getResourceHierarchy()); + } else { + dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + } + if (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { + // Inter-service + if (!bDeclareClientField) { + // Declare a client field to connect to the destination resource of push transfer. + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + if (component != null) { + // A component is created for this resource. + component.addField(clientField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); + } + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the destination resource of push transfer. + FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + if (component != null) { + // A component is created for this resource. + component.addField(dstRefField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField)); + } + } + } + } + } + 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 input and output resources are 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; + } + } + 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; + } + } + String srcResName = getComponentName(srcRes.getResourceHierarchy()); + if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { + if (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { + // Inter-service + if (!bDeclareClientField) { + // Declare a client field to connect to the source resource of pull transfer. + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + if (component != null) { + // A component is created for this resource. + component.addField(clientField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); + } + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the source resource of pull transfer. + FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + if (component != null) { + // A component is created for this resource. + component.addField(srcRefField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); + } + } + } else { + // Declare an update method in the type of the destination resource. + ArrayList vars = new ArrayList<>(); + String srcName = srcRes.getResourceName(); + Type srcType = srcRes.getResourceStateType(); + VariableDeclaration param = new VariableDeclaration(srcType, srcName); + param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); + vars.add(param); + for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { + if (!refRes.equals(resourceNode.getOutSideResource())) { + param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); + param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); + vars.add(param); + } + } + MethodDeclaration update = null; + if (component != null) { + // A component is created for this resource. + update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, vars); + } else { + // No component is created for this resource. + String resourceName = getComponentName(resourceNode.getResourceHierarchy()); + update = new MethodDeclaration("update" + resourceName + "From" + srcResName, false, typeVoid, vars); + } + for (ChannelMember cm: ((ChannelNode) re.getDestination()).getChannel().getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource())) { + if (cm.getStateTransition().isRightUnary()) { + update.addAnnotation(new Annotation("PUT")); + } else { + update.addAnnotation(new Annotation("POST")); + } + } + } + if (re.getDestination().getIndegree() > 1 + || (re.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // Declare a field to cache the state of the source resource in the type of the destination resource. + ResourcePath cacheRes = ((ResourceNode) re.getSource()).getOutSideResource(); + FieldDeclaration cacheField = new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes)); + if (component != null) { + // A component is created for this resource. + component.addField(cacheField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), cacheField)); + } + if (re.getDestination().getIndegree() > 1) { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); + } + } + if (component != null) { + // A component is created for this resource. + component.addMethod(update); + } else { + // No component is created for this resource. + String updateMethodName = update.getName(); + Map nameToMethod = updates.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + updates.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); + } + if (nameToMethod.get(updateMethodName) == null) { + nameToMethod.put(updateMethodName, update); + } + } + } + } } // Declare the input method in each resource and the root resource. for (Channel ch : model.getIOChannels()) { for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { - if (rn.getInSideResources().contains(cm.getResource())) { + if (!cm.isOutside()) { + if (priorMemberForInputChannel.get(ch) == null) { + priorMemberForInputChannel.put(ch, cm); // The receiver of the input event when multiple output resources are defined for the channel. + } + } + } + for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource())) { Expression message = cm.getStateTransition().getMessageExpression(); if (message instanceof Term) { // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getInputMethodResourcePathaAndPathParams(cm.getResource(), resInputParams, rootInputParams); + String resourcePath = getInputMethodResourcePathAndPathParams(cm.getResource(), resInputParams, rootInputParams); if (resourcePath.indexOf('/') > 0) { - resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); } else { - resourcePath = "\"" + resourcePath + "\""; + resourcePath = ""; } for (Map.Entry varEnt: message.getVariables().entrySet()) { Variable var = varEnt.getValue(); @@ -557,36 +648,52 @@ String paramName = var.getName(); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); resInputParams.add(param); - param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); - rootInputParams.add(param); + if (!resourcePath.contains("{" + paramName+ "}")) { + param = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); + rootInputParams.add(param); + } } } - if (rn.getResourceHierarchy().getParent() != null && rn.getResourceHierarchy().getParent().getParent() != null) { - MethodDeclaration input = new MethodDeclaration(((Term) message).getSymbol().getImplName(), - false, typeVoid, resInputParams); + if (resourceNode.getResourceHierarchy().getParent() != null && resourceNode.getResourceHierarchy().getParent().getParent() != null) { + String inputMethodName = ((Term) message).getSymbol().getImplName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); + } + MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams); if (component != null) { // A component is created for this resource. component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); + Map nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); + } + if (nameToMethod.get(inputMethodName) == null) { + nameToMethod.put(inputMethodName, input); + } } } // For the root resource. - String str = ((Term) message).getSymbol().getImplName(); - MethodDeclaration inputAccessor = new MethodDeclaration(str, false, typeVoid, rootInputParams); - if (cm.getStateTransition().isRightUnary()) { - inputAccessor.addAnnotation(new Annotation("PUT")); - } else { - inputAccessor.addAnnotation(new Annotation("POST")); + if (priorMemberForInputChannel.get(ch) ==null || cm == priorMemberForInputChannel.get(ch)) { + // If cm is the receiver of the input event. + priorMemberForInputChannel.put(ch, cm); + String messageSymbol = ((Term) message).getSymbol().getImplName(); + MethodDeclaration inputAccessor = new MethodDeclaration(messageSymbol, false, typeVoid, rootInputParams); + if (cm.getStateTransition().isRightUnary()) { + inputAccessor.addAnnotation(new Annotation("PUT")); + } else { + inputAccessor.addAnnotation(new Annotation("POST")); + } + if (resourcePath.length() > 0) { + inputAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); + } + inputAccessors.put(resourceNode.getResourceHierarchy(), inputAccessor); } - if (ch.getAllSelectors().size() > 0) { - inputAccessor.addAnnotation(new Annotation("Path", resourcePath)); - } - inputAccessors.put(rn.getResourceHierarchy(), inputAccessor); } else if (message instanceof Variable) { // In each resource. ArrayList resInputParams = new ArrayList<>(); @@ -607,36 +714,50 @@ v++; } if (cm.getResource().getResourceHierarchy().getParent() != null && cm.getResource().getResourceHierarchy().getParent().getParent() != null) { - MethodDeclaration input = new MethodDeclaration(((Variable) message).getName(), - false, typeVoid, null); + String inputMethodName = ((Variable) message).getName(); + if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { + inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); + } + MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, null); if (component != null) { // A component is created for this resource. component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry<>(cm.getResource().getParent().getResourceHierarchy(), input)); + Map nameToMethod = inputs.get(cm.getResource().getParent().getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + inputs.put(cm.getResource().getParent().getResourceHierarchy(), nameToMethod); + } + if (nameToMethod.get(inputMethodName) == null) { + nameToMethod.put(inputMethodName, input); + } } } // For the root resource. - ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getGetterResourcePathAndPathParams(cm.getResource(), rootInputParams); - if (resourcePath.indexOf('/') > 0) { - resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; - } else { - resourcePath = "\"" + resourcePath + "\""; + if (priorMemberForInputChannel.get(ch) ==null || cm == priorMemberForInputChannel.get(ch)) { + // If cm is the receiver of the input event. + priorMemberForInputChannel.put(ch, cm); + ArrayList rootInputParams = new ArrayList<>(); + String resourcePath = getGetterResourcePathAndPathParams(cm.getResource(), rootInputParams); + if (resourcePath.indexOf('/') > 0) { + resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; + } + String messageSymbol = ((Variable) message).getName(); + MethodDeclaration inputAccessor = new MethodDeclaration(messageSymbol, false, typeVoid, rootInputParams); + if (cm.getStateTransition().isRightUnary()) { + inputAccessor.addAnnotation(new Annotation("PUT")); + } else { + inputAccessor.addAnnotation(new Annotation("POST")); + } + if (resourcePath.length() > 0) { + inputAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); + } + inputAccessors.put(resourceNode.getResourceHierarchy(), inputAccessor); } - String str = ((Variable) message).getName(); - MethodDeclaration inputAccessor = new MethodDeclaration(str, false, typeVoid, rootInputParams); - if (cm.getStateTransition().isRightUnary()) { - inputAccessor.addAnnotation(new Annotation("PUT")); - } else { - inputAccessor.addAnnotation(new Annotation("POST")); - } - if (ch.getAllSelectors().size() > 0) { - inputAccessor.addAnnotation(new Annotation("Path", resourcePath)); - } - inputAccessors.put(rn.getResourceHierarchy(), inputAccessor); } } } @@ -648,9 +769,18 @@ resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); } + // Add leaf update methods to the parent components. + for (Map.Entry> entry: updates.entrySet()) { + for (MethodDeclaration update: entry.getValue().values()) { + resourceComponents.get(entry.getKey()).addMethod(update); + } + } + // Add leaf input methods to the parent components. - for (Map.Entry entry: inputs) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); + for (Map.Entry> entry: inputs.entrySet()) { + for (MethodDeclaration input: entry.getValue().values()) { + resourceComponents.get(entry.getKey()).addMethod(input); + } } // Add leaf reference fields to the parent components. @@ -751,14 +881,14 @@ private static List addConstructorParameters(ResourceHierarchy resource, Map resourceComponents, Map resourceConstructors, - List> constructorParams) { + Map> constructorParams) { List params = new ArrayList<>(); for (ResourceHierarchy child: resource.getChildren()) { params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams)); } - for (Map.Entry paramEnt: constructorParams) { - if (paramEnt.getKey().equals(resource)) { - params.add(paramEnt.getValue()); + if (constructorParams.get(resource) != null) { + for (VariableDeclaration param: constructorParams.get(resource).values()) { + params.add(param); } } if (params.size() > 0) { @@ -808,7 +938,7 @@ return resPath.getResourceHierarchy().toResourcePath(params); } - private static String getInputMethodResourcePathaAndPathParams(ResourcePath resPath, ArrayList resInputParams, + private static String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList resInputParams, ArrayList rootInputParams) { int v = 1; List params = new ArrayList<>(); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index e04d2c6..fd766cc 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -95,7 +95,14 @@ } if (pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { // for push data transfer - MethodDeclaration update = getUpdateMethod(dstComponent, srcComponent); + MethodDeclaration update = null; + if (dstComponent == null) { + String dstParentResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); + dstComponent = componentMap.get(dstParentResourceName); + update = getUpdateMethod(dstComponent, dstResourceName, srcResourceName); + } else { + update = getUpdateMethod(dstComponent, null, srcResourceName); + } if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst side resource (when every incoming edge is in push style) Expression updateExp = null; @@ -136,16 +143,47 @@ } // Add statements to the update method. String[] sideEffects = new String[] {""}; - String curState = updateExp.toImplementation(sideEffects); - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; + String newState = updateExp.toImplementation(sideEffects); + if (JerseyCodeGenerator.generatesComponent(outRes)) { + String updateStatement; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + } else { + updateStatement = sideEffects[0] + "this.value = " + newState + ";"; + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + // add an update statement of the state of dst side resource. + update.addFirstStatement(updateStatement); + } } else { - updateStatement = sideEffects[0] + "this.value = " + curState + ";"; - } - if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { - // add an update statement of the state of dst side resource. - update.addFirstStatement(updateStatement); + String updateStatement = ""; + if (sideEffects[0] != null) { + updateStatement = sideEffects[0]; + updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes))); + } + if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + updateStatement += "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + // add an update statement of the state of dst side resource. + update.addFirstStatement(updateStatement); + } } } if (resToCh.getDestination().getIndegree() > 1 @@ -222,10 +260,6 @@ } if (((StoreAttribute) dst.getAttribute()).isStored()) { // returns the state stored in a field. - if (dstComponent == null) { - String dstParentResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); - dstComponent = componentMap.get(dstParentResourceName); - } MethodDeclaration getter = null; if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { getter = getMethod(dstComponent, "getValue"); @@ -257,7 +291,13 @@ } else { httpMethod = "post"; } - for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent)) { + String srcName = null; + if (srcComponent == null) { + String srcParentResourceName = JerseyCodeGenerator.getComponentName(src.getResourceHierarchy().getParent()); + srcComponent = componentMap.get(srcParentResourceName); + srcName = srcResourceName; + } + for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent, srcName)) { if (srcUpdate != null) { List>> params = new ArrayList<>(); Set referredSet = referredResources.get(srcUpdate); @@ -281,10 +321,6 @@ } } } - String srcResName = null; - if (dst.getIndegree() > 1) { - srcResName = srcResourceName; - } if (!chainedCalls.contains(srcUpdate)) { // The first call to an update method in this method // Value of the source side (input side) resource. @@ -293,7 +329,7 @@ srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResName), + JerseyCodeGenerator.toVariableName(srcResourceName), httpMethod)); chainedCalls.add(srcUpdate); } else { @@ -304,7 +340,7 @@ srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResName), + JerseyCodeGenerator.toVariableName(srcResourceName), httpMethod)); } srcUpdate.addThrow("JsonProcessingException"); @@ -331,10 +367,6 @@ params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); } } - String srcResName = null; - if (dst.getIndegree() > 1) { - srcResName = srcResourceName; - } if (!chainedCalls.contains(srcInput)) { // First call to an update method in this method // Value of the source side (input side) resource. @@ -343,7 +375,7 @@ srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResName), + JerseyCodeGenerator.toVariableName(srcResourceName), httpMethod)); chainedCalls.add(srcInput); } else { @@ -354,7 +386,7 @@ srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResName), + JerseyCodeGenerator.toVariableName(srcResourceName), httpMethod)); } srcInput.addThrow("JsonProcessingException"); @@ -512,13 +544,13 @@ MethodDeclaration input = null; if (JerseyCodeGenerator.generatesComponent(resource)) { // A component is generated for this resource. - input = getInputMethod(component, out); + input = getInputMethod(component, out, entry.getKey().getOutputChannelMembers().size()); } else { // No component is generated for this resource. ResourceHierarchy parent = resource.getParent(); if (parent != null) { TypeDeclaration parentType = componentMap.get(JerseyCodeGenerator.getComponentName(parent)); - input = getInputMethod(parentType, out); + input = getInputMethod(parentType, out, entry.getKey().getOutputChannelMembers().size()); } } if (input != null) { @@ -566,39 +598,45 @@ input.addStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - // ToDo. + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; - } else { - if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - 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(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - 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 { - updateStatement = sideEffects[0] + "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; - } - if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { - input.addStatement(updateStatement); - } + updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource))); + } + if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + 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 += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + 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 += sideEffects2[0]; + } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { + updateStatement += "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; + } + if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { + input.addStatement(updateStatement); } } if (out.getResource().getParent() != null && out.getResource().getParent().getParent() != null) { // In the root resource - MethodDeclaration inputAccessor = getMethod(componentMap.get(JerseyCodeGenerator.getComponentName(resource.getRoot())), input.getName()); + Expression message = out.getStateTransition().getMessageExpression(); + String inputAccessorName = input.getName(); + if (message instanceof Term) { + inputAccessorName = ((Term) message).getSymbol().getImplName(); + } else if (message instanceof Variable) { + inputAccessorName = ((Variable) message).getName(); + } + MethodDeclaration inputAccessor = getMethod(componentMap.get(JerseyCodeGenerator.getComponentName(resource.getRoot())), inputAccessorName); if (inputAccessor != null) { Expression resExp = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(out.getResource(), out.getResource().getRoot()); String args = ""; @@ -612,8 +650,7 @@ resExp = ((Term) resExp).getChild(0); } String resourceAccess = resExp.toImplementation(new String[] {null}); - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); + if (message instanceof Term) { for (Variable var: message.getVariables().values()) { args += delimiter + var.getName(); delimiter = ", "; @@ -852,9 +889,13 @@ return null; } - private static MethodDeclaration getUpdateMethod(TypeDeclaration component, TypeDeclaration from) { + private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String dstResName, String srcResName) { for (MethodDeclaration m: component.getMethods()) { - if (m.getName().equals("update" + from.getTypeName())) return m; + if (dstResName == null) { + if (m.getName().equals("updateFrom" + srcResName)) return m; + } else { + if (m.getName().equals("update" + dstResName + "From" + srcResName)) return m; + } } return null; } @@ -866,11 +907,17 @@ return null; } - private static List getUpdateMethods(TypeDeclaration component) { + private static List getUpdateMethods(TypeDeclaration component, String resName) { List updates = new ArrayList<>(); for (MethodDeclaration m: component.getMethods()) { - if (m.getName().startsWith("update")) { - updates.add(m); + if (resName == null) { + if (m.getName().startsWith("updateFrom")) { + updates.add(m); + } + } else { + if (m.getName().startsWith("update" + resName + "From")) { + updates.add(m); + } } } return updates; @@ -904,7 +951,7 @@ // I/O channel for (ChannelMember out: channel.getOutputChannelMembers()) { if (resource.getInSideResources().contains(out.getResource())) { - MethodDeclaration input = getInputMethod(component, out); + MethodDeclaration input = getInputMethod(component, out, channel.getOutputChannelMembers().size()); inputs.add(input); } } @@ -912,15 +959,19 @@ return inputs; } - private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember out) { - MethodDeclaration input = null; - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); - input = getMethod(component, message.getSymbol().getImplName()); - } else if (out.getStateTransition().getMessageExpression() instanceof Variable) { - Variable message = (Variable) out.getStateTransition().getMessageExpression(); - input = getMethod(component, message.getName()); + private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember cm, int outNumber) { + String inputMethodName = null; + if (cm.getStateTransition().getMessageExpression() instanceof Term) { + Term message = (Term) cm.getStateTransition().getMessageExpression(); + inputMethodName = message.getSymbol().getImplName(); + } else if (cm.getStateTransition().getMessageExpression() instanceof Variable) { + Variable message = (Variable) cm.getStateTransition().getMessageExpression(); + inputMethodName = message.getName(); } + if (outNumber > 1) { + inputMethodName += "For" + JerseyCodeGenerator.getComponentName(cm.getResource().getResourceHierarchy()); + } + MethodDeclaration input = getMethod(component, inputMethodName); return input; } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java index a778387..7f418be 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java @@ -102,6 +102,8 @@ if (!params.containsAll(channelMember.getResource().getPathParams())) { channelMember.setOutside(true); } + } else { + channelMember.setOutside(true); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java index b241023..6be124c 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java @@ -13,7 +13,7 @@ protected Set rootResourceNodes = null; protected Set rootChannelNodes = null; protected Map channelNodeMap = null; - protected Map resourceNodeMap = null; + protected Map resourceNodeMap = null; public DataFlowGraph() { super(); @@ -26,7 +26,7 @@ public ResourceNode addResourceNode(ResourceNode parent, DataTransferChannel outSideChannel, ResourcePath outSideResource) { - ResourceNode node = resourceNodeMap.get(outSideResource); + ResourceNode node = resourceNodeMap.get(System.identityHashCode(outSideResource)); if (node != null) return node; node = new ResourceNode(parent, outSideChannel, outSideResource); addNode(node); @@ -35,14 +35,14 @@ } else { parent.addChild(node); } - resourceNodeMap.put(outSideResource, node); + resourceNodeMap.put(System.identityHashCode(outSideResource), node); return node; } public ResourceNode addResourceNode(ResourceNode parent, Map inSide, Map.Entry outSide) { - ResourceNode node = resourceNodeMap.get(outSide.getValue()); + ResourceNode node = resourceNodeMap.get(System.identityHashCode(outSide.getValue())); if (node != null) return node; node = new ResourceNode(parent, inSide, outSide); addNode(node); @@ -51,7 +51,7 @@ } else { parent.addChild(node); } - resourceNodeMap.put(outSide.getValue(), node); + resourceNodeMap.put(System.identityHashCode(outSide.getValue()), node); return node; } @@ -70,7 +70,7 @@ } public ResourceNode getResourceNode(ResourcePath outSide) { - return resourceNodeMap.get(outSide); + return resourceNodeMap.get(System.identityHashCode(outSide)); } public ChannelNode getChannelNode(DataTransferChannel channel) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java index b339a66..3bf7c9e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferModel.java @@ -13,7 +13,7 @@ public class DataTransferModel extends DataConstraintModel { public DataFlowGraph getDataFlowGraph() { DataFlowGraph dataFlowGraph = new DataFlowGraph(); - Map> resourceMap = new HashMap<>(); + Map>> resourceMap = new HashMap<>(); for (Channel channel: getChannels()) { addResourceToChannelEdges(dataFlowGraph, channel, null, resourceMap); } @@ -27,13 +27,38 @@ } private void addResourceToChannelEdges(DataFlowGraph dataFlowGraph, Channel dstChannel, ChannelNode parentChannelNode, - Map> resourceMap) { - DataTransferChannel dstDfChannel = (DataTransferChannel)dstChannel; + Map>> resourceMap) { + DataTransferChannel dstDfChannel = (DataTransferChannel) dstChannel; ChannelNode dstChannelNode = dataFlowGraph.addChannelNode(parentChannelNode, dstDfChannel); - Set inputResources = dstDfChannel.getInputResources(); - for (ResourcePath srcRes: inputResources) { - ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, resourceMap); - dataFlowGraph.addEdge(srcResNode, dstChannelNode); + for (ResourcePath srcRes: dstDfChannel.getInputResources()) { + Map> chToNodes = resourceMap.get(srcRes.getResourceHierarchy()); + if (srcRes.getNumberOfParameters() == 0) { + if (chToNodes == null || chToNodes.get(null) == null) { + // ResourcePath without parameter corresponds to a global ResourceNode. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, null, resourceMap); + dataFlowGraph.addEdge(srcResNode, dstChannelNode); + } + } else { + if (chToNodes == null || chToNodes.get(dstChannel) == null) { + // There is no channel-local ResourcePath. + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, resourceMap); + dataFlowGraph.addEdge(srcResNode, dstChannelNode); + } else { + // There already has been a channel-local ResourceNode. + Set nodes = chToNodes.get(dstChannel); // channel-local ResourceNodes. + boolean bExists = false; + for (ResourceNode node: nodes) { + if (node.getOutSideResource().toString().equals(srcRes.toString())) { + bExists = true; + break; + } + } + if (!bExists) { + ResourceNode srcResNode = addResourceNodes(dataFlowGraph, srcRes, dstDfChannel, resourceMap); + dataFlowGraph.addEdge(srcResNode, dstChannelNode); + } + } + } } for (Channel childChannel: dstDfChannel.getChildren()) { addResourceToChannelEdges(dataFlowGraph, childChannel, dstChannelNode, resourceMap); @@ -41,19 +66,80 @@ } private void addChannelToResourceEdges(DataFlowGraph dataFlowGraph, Channel srcChannel, ChannelNode parentChannelNode, - Map> resourceMap) { - DataTransferChannel srcDfChannel = (DataTransferChannel)srcChannel; - Set outputResources = srcDfChannel.getOutputResources(); + Map>> resourceMap) { + DataTransferChannel srcDfChannel = (DataTransferChannel) srcChannel; ChannelNode srcChannelNode = dataFlowGraph.addChannelNode(parentChannelNode, srcDfChannel); - for (ResourcePath dstRes: outputResources) { - Set dstResSet = resourceMap.get(dstRes.getResourceHierarchy()); // ResourceNodes that have the same ResourceHierarchy. - if (dstResSet == null || dstResSet.size() == 0) { - ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, resourceMap); - if (dstResSet == null) { - dstResSet = new HashSet<>(); - resourceMap.put(dstRes.getResourceHierarchy(), dstResSet); + for (ResourcePath dstRes: srcDfChannel.getOutputResources()) { + Map> chToNodes = resourceMap.get(dstRes.getResourceHierarchy()); // ResourceNodes that have the same ResourceHierarchy. + Set dstResSet = new HashSet<>(); + if (dstRes.getNumberOfParameters() == 0) { + // ResourcePath without parameter corresponds to a global ResourceNode. + if (chToNodes == null) { + // Create a new global ResourceNode. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, null, resourceMap); + dstResSet.add(dstResNode); + } else { + // Select global ResourceNodes. + dstResSet.addAll(chToNodes.get(null)); } - dstResSet.add(dstResNode); + } else { + if (chToNodes == null) { + // There is no corresponding ResourceNode. + // Create new ResourceNode. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, resourceMap); + dstResSet.add(dstResNode); + } else { + // There already has been a ResourceNode. + if (chToNodes.get(srcDfChannel) != null && chToNodes.get(srcDfChannel).size() > 0) { + // There already has been a channel-local ResourceNode. + for (ResourceNode localResNode: chToNodes.get(srcDfChannel)) { + for (ResourcePath localResPath: localResNode.getInSideResources()) { + if (localResPath.toString().equals(dstRes.toString())) { + // Channel-local ResourcePath should be identical, and the identical ResourcePath is selected on top priority. + dstResSet.add(localResNode); + } + } + } + } + // Search a common channel-local ancestor. + if (dstResSet.size() == 0) { + ResourcePath dstParent = dstRes.getParent(); + while (dstParent != null && dstParent.getNumberOfParameters() > 0) { + if (resourceMap.get(dstParent.getResourceHierarchy()) != null && resourceMap.get(dstParent.getResourceHierarchy()).get(srcDfChannel) != null) { + for (ResourceNode localParentNode: resourceMap.get(dstParent.getResourceHierarchy()).get(srcDfChannel)) { + if (localParentNode.getOutSideResource().toString().equals(dstParent.toString())) { + // There already has been a common channel-local ancestor. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, resourceMap); + dstResSet.add(dstResNode); + break; + } + for (ResourcePath localParentPath: localParentNode.getInSideResources()) { + if (localParentPath.toString().equals(dstParent.toString())) { + // There already has been a common channel-local ancestor. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, resourceMap); + dstResSet.add(dstResNode); + break; + } + } + if (dstResSet.size() > 0) break; + } + if (dstResSet.size() > 0) break; + } + dstParent = dstParent.getParent(); + } + } + if (dstResSet.size() == 0) { + for (Set nodes: chToNodes.values()) { + // Select all corresponding ResourceNodes. + dstResSet.addAll(nodes); + } + } + if (dstResSet.size() == 0) { + // Otherwise create a new ResourceNode. + ResourceNode dstResNode = addResourceNodes(dataFlowGraph, dstRes, srcDfChannel, resourceMap); + dstResSet.add(dstResNode); + } + } } for (ResourceNode dstResNode: dstResSet) { dstResNode.addInSideResource(srcDfChannel, dstRes); @@ -64,22 +150,96 @@ addChannelToResourceEdges(dataFlowGraph, childChannel, srcChannelNode, resourceMap); } } - - private ResourceNode addResourceNodes(DataFlowGraph dataFlowGraph, ResourcePath resPath, DataTransferChannel dfChannel, - Map> resourceMap) { + + private ResourceNode addResourceNodes(DataFlowGraph dataFlowGraph, ResourcePath resPath, DataTransferChannel dfChannel, + Map>> resourceMap) { ResourceNode resNode = null; + if (resPath.getNumberOfParameters() == 0) { + dfChannel = null; + } if (resPath.getParent() == null) { resNode = dataFlowGraph.addResourceNode(null, dfChannel, resPath); } else { - ResourceNode parent = addResourceNodes(dataFlowGraph, resPath.getParent(), null, resourceMap); + // Search an identical parent ResourceNode. + ResourceNode parent = null; + DataTransferChannel parentDfChannel = dfChannel; + if (resPath.getParent().getNumberOfParameters() == 0) { + parentDfChannel = null; + } + if (resourceMap.get(resPath.getResourceHierarchy().getParent()) != null) { + Set nodes = resourceMap.get(resPath.getResourceHierarchy().getParent()).get(parentDfChannel); + if (nodes != null) { + for (ResourceNode node: nodes) { + if (node.getOutSideResource().toString().equals(resPath.getParent().toString())) { + parent = node; + break; + } + for (ResourcePath r: node.getInSideResources()) { + if (r.toString().equals(resPath.getParent().toString())) { + parent = node; + break; + } + } + if (parent != null) break; + } + } + } + if (parent == null) { + parent = addResourceNodes(dataFlowGraph, resPath.getParent(), parentDfChannel, resourceMap); + } resNode = dataFlowGraph.addResourceNode(parent, dfChannel, resPath); } - Set resSet = resourceMap.get(resPath.getResourceHierarchy()); - if (resSet == null) { - resSet = new HashSet<>(); - resourceMap.put(resPath.getResourceHierarchy(), resSet); + Map> chToNodes = resourceMap.get(resPath.getResourceHierarchy()); + if (chToNodes == null) { + chToNodes = new HashMap<>(); + resourceMap.put(resPath.getResourceHierarchy(), chToNodes); } - resSet.add(resNode); + Set nodes = chToNodes.get(dfChannel); + if (nodes == null) { + nodes = new HashSet<>(); + chToNodes.put(dfChannel, nodes); + } + nodes.add(resNode); return resNode; } + +// private ResourceNode addResourceNodes(DataFlowGraph dataFlowGraph, ResourcePath resPath, DataTransferChannel dfChannel, +// Map>> resourceMap) { +// if (resPath.getNumberOfParameters() == 0) { +// // ResourcePath without parameter corresponds to a global ResourceNode. +// dfChannel = null; +// } +// if (resourceMap.get(resPath.getResourceHierarchy()) != null && resourceMap.get(resPath.getResourceHierarchy()).get(dfChannel) != null) { +// Set nodes = resourceMap.get(resPath.getResourceHierarchy()).get(dfChannel); +// for (ResourceNode node: nodes) { +// if (node.getOutSideResource().toString().equals(resPath.toString())) { +// return node; +// } +// for (ResourcePath res: node.getInSideResources()) { +// if (res.toString().toString().equals(resPath.toString())) { +// return node; +// } +// } +// } +// } +// ResourceNode resNode = null; +// if (resPath.getParent() == null) { +// resNode = dataFlowGraph.addResourceNode(null, dfChannel, resPath); +// } else { +// ResourceNode parent = addResourceNodes(dataFlowGraph, resPath.getParent(), dfChannel, resourceMap); +// resNode = dataFlowGraph.addResourceNode(parent, dfChannel, resPath); +// } +// Map> chToNodes = resourceMap.get(resPath.getResourceHierarchy()); +// if (chToNodes == null) { +// chToNodes = new HashMap<>(); +// resourceMap.put(resPath.getResourceHierarchy(), chToNodes); +// } +// Set nodes = chToNodes.get(dfChannel); +// if (nodes == null) { +// nodes = new HashSet<>(); +// chToNodes.put(dfChannel, nodes); +// } +// nodes.add(resNode); +// return resNode; +// } }