diff --git a/models/designPattern/Flyweight.Json b/models/designPattern/Flyweight.Json index f049a7b..0f8e1fa 100644 --- a/models/designPattern/Flyweight.Json +++ b/models/designPattern/Flyweight.Json @@ -6,7 +6,7 @@ { "src": "Main.AlchemistShop.PotionFactory.{Potion}", "dst": "Main.AlchemistShop", - "multiplicity": "1:1" + "multiplicity": "*:*" } ], "transfer": { @@ -23,7 +23,7 @@ "relations": [], "transfer": { "src": "Main.AlchemistShop.TopShelf.{Potion}.Data", - "dst": "Main.Data", + "dst": "Main.AlchemistShop.Data", "data": { "name": "data" }, diff --git a/src/main/java/generators/ASTGenerator.java b/src/main/java/generators/ASTGenerator.java index d6aa1da..cf5fc92 100644 --- a/src/main/java/generators/ASTGenerator.java +++ b/src/main/java/generators/ASTGenerator.java @@ -137,26 +137,26 @@ // Construct coordinator method MethodDeclaration coordionator = null; - if (!primitivePullDelta.isMultipleDefinition() || pullEdge1.toMany()) { - coordionator = createMethod(class1, updateMethodPrefix + toComponentName(pullEdge2.getName())); - } else { + if (primitivePullDelta.isMultipleDefinition() && !pullEdge1.toMany() && !primitivePullDelta.isMultipleTransfer()) { coordionator = createMethod(class1, addMethodPrefix + toComponentName(pullEdge2.getName())); + } else { + coordionator = createMethod(class1, updateMethodPrefix + toComponentName(pullEdge2.getName())); } FieldAccess field3 = new FieldAccess(new ThisExpression(), field13.getName()); // this.name3 FieldAccess field2 = new FieldAccess(field12.getName()); List args = new ArrayList<>(); - if (pullEdge2.toMany()) { + if (primitivePullDelta.isMultipleDefinition() && !pullEdge1.toMany() && !primitivePullDelta.isMultipleTransfer()) { VariableDeclaration idVar = new VariableDeclaration(keyType, pullEdge2.getName() + idPostfix); coordionator.addParameter(idVar); args.add(new Variable(idVar.getName())); // name2.getName3(name3Id) } MethodInvocation callGetter = new MethodInvocation(field2, getter.getName(), args); // name2.getName3() if (!primitivePullDelta.isMultipleDefinition()) { - Assignment assignment = new Assignment(field3, callGetter); // this.name3 = name2.getName3(); + Assignment assignment = new Assignment(field3, callGetter); // this.name3 = name2.getName3(); ExpressionStatement assignmentStatement = new ExpressionStatement(assignment); coordionator.addUniqueStatement(assignmentStatement); } else { - if (!pullEdge1.toMany()) { + if (!pullEdge1.toMany() && !primitivePullDelta.isMultipleTransfer()) { VariableDeclaration idVar = new VariableDeclaration(keyType, pullEdge2.getName() + idPostfix); args = new ArrayList<>(); args.add(new Variable(idVar.getName())); @@ -164,17 +164,34 @@ coordionator.addUniqueStatement(new ExpressionStatement(new MethodInvocation(field3, mapPut, args))); // this.name3Map.put(name3Id, name2.getName3()); } else { EnhancedForStatement collectionLoop = new EnhancedForStatement(); // for (key2 loopVar: name2Map.keySet()) - String loopVarName = pullEdge1.getName() + idPostfix; - keyType = ((MapType) field12.getType()).getKeyType(); + String loopVarName = null; + if (pullEdge1.toMany()) { + loopVarName = pullEdge1.getName() + idPostfix; + keyType = ((MapType) field12.getType()).getKeyType(); + } else { + loopVarName = pullEdge2.getName() + idPostfix; + keyType = ((MapType) field13.getType()).getKeyType(); + } VariableDeclaration loopVar = new VariableDeclaration(keyType, loopVarName); - MethodInvocation keysGetter = new MethodInvocation(field2, mapKeySet); + MethodInvocation keysGetter = null; + if (pullEdge1.toMany()) { + keysGetter = new MethodInvocation(field2, mapKeySet); + } else { + keysGetter = new MethodInvocation(field3, mapKeySet); + } args = new ArrayList<>(); args.add(new Variable(loopVarName)); - MethodInvocation valueGetter = new MethodInvocation(field2, mapGet, args); + if (pullEdge1.toMany()) { + MethodInvocation valueGetter = new MethodInvocation(field2, mapGet, args); + args = new ArrayList<>(); + args.add(new Variable(loopVarName)); + args.add(new MethodInvocation(valueGetter, getter.getName())); + } else { + args = new ArrayList<>(); + args.add(new Variable(loopVarName)); + args.add(new MethodInvocation(field2, getter.getName(), List.of(new Variable(loopVarName)))); + } Block loopBody = new Block(); - args = new ArrayList<>(); - args.add(new Variable(loopVarName)); - args.add(new MethodInvocation(valueGetter, getter.getName())); loopBody.addStatement(new ExpressionStatement(new MethodInvocation(field3, mapPut, args))); // this.name3Map.put(loopVar, name2Map.get(loopVar).getName3()); collectionLoop.setParameter(loopVar); collectionLoop.setExpression(keysGetter); @@ -200,9 +217,16 @@ models.algebra.Type type1 = codebase.getComponentType(name1); models.algebra.Type type2 = codebase.getComponentType(name2); models.algebra.Type type3 = codebase.getComponentType(name3); - FieldDeclaration field12 = createField(class1, pullEdge.getName(), type2); // class1 -> class2 (PULL) + FieldDeclaration field12 = null; + if (!pullEdge.toMany()) { + field12 = createField(class1, pullEdge.getName(), type2); // class1 -> class2 (PULL) + } else { + MapType typeKeyToType2 = codebase.getMapType(pullEdge.getKeyTypeName(), name2); + field12 = createField(class1, pullEdge.getName() + mapPostfix, typeKeyToType2); // class3 -> {class2} (PULL) + } FieldDeclaration field13 = null; models.algebra.Type keyType = null; + models.algebra.Type keyType2 = null; if (!pushEdge.toMany()) { field13 = createField(class1, pushEdge.getName(), type3); // class1 -> class3 (PUSH) } else { @@ -210,21 +234,40 @@ keyType = typeKeyToType3.getKeyType(); field13 = createField(class1, pushEdge.getName() + mapPostfix, typeKeyToType3); // class1 -> {class3} (PUSH) } - FieldDeclaration field32 = createField(class3, pullEdge.getName(), type2); // class3 -> class2 (define) + FieldDeclaration field32 = null; + if (!primitivePullPushDelta.isMultipleDefinition()) { + field32 = createField(class3, pullEdge.getName(), type2); // class3 -> class2 (define) + } else { + MapType typeKeyToType2 = codebase.getMapType(pullEdge.getKeyTypeName(), name2); + keyType2 = typeKeyToType2.getKeyType(); + field32 = createField(class3, pullEdge.getName() + mapPostfix, typeKeyToType2); // class3 -> {class2} (define) + } // Construct setter method MethodDeclaration setter = null; + VariableDeclaration param2Id = null; if (!pushEdge.toMany() || primitivePullPushDelta.isMultipleDefinition()) { setter = createMethod(class3, setterPrefix + toComponentName(name2)); + if (primitivePullPushDelta.isMultipleDefinition()) { + param2Id = new VariableDeclaration(keyType2, toVariableName(name2) + idPostfix); + setter.addParameter(param2Id); + } } else { setter = createConstructor(class3); } VariableDeclaration param2 = new VariableDeclaration(type2, toVariableName(name2)); setter.addParameter(param2); - FieldAccess field2 = new FieldAccess(new ThisExpression(), field32.getName()); // this.name2 - Assignment assignment = new Assignment(field2, new Variable(toVariableName(name2))); // this.name2 = name2; - ExpressionStatement assignmentStatement = new ExpressionStatement(assignment); - setter.addUniqueStatement(assignmentStatement); + FieldAccess field2 = new FieldAccess(new ThisExpression(), field32.getName()); + if (!primitivePullPushDelta.isMultipleDefinition()) { + Assignment assignment = new Assignment(field2, new Variable(toVariableName(name2))); // this.name2 = name2; + ExpressionStatement assignmentStatement = new ExpressionStatement(assignment); + setter.addUniqueStatement(assignmentStatement); + } else { + List args = new ArrayList<>(); + args.add(new Variable(param2Id.getName())); + args.add(new Variable(toVariableName(name2))); + setter.addUniqueStatement(new ExpressionStatement(new MethodInvocation(field2, mapPut, args))); // name2Map.put(name2Id, name2); + } // Construct coordinator method MethodDeclaration coordionator = null; @@ -233,29 +276,38 @@ } else { coordionator = createMethod(class1, addMethodPrefix + toComponentName(name3)); } - List args = new ArrayList<>(); - args.add(new FieldAccess(field12.getName())); FieldAccess field3 = new FieldAccess(field13.getName()); if (!pushEdge.toMany() || primitivePullPushDelta.isMultipleDefinition()) { if (!primitivePullPushDelta.isMultipleDefinition()) { - MethodInvocation callSetter = new MethodInvocation(field3, setter.getName(), args); // name3.setName2(name2) + List args = new ArrayList<>(); + args.add(new FieldAccess(field12.getName())); + MethodInvocation callSetter = new MethodInvocation(field3, setter.getName(), args); // name3.setName2(name2) coordionator.addUniqueStatement(new ExpressionStatement(callSetter)); } else { - EnhancedForStatement broadcastLoop = new EnhancedForStatement(); // for (type3 loopVar: name3Map.values()) - String loopVarName = pushEdge.getName(); - VariableDeclaration loopVar = new VariableDeclaration(type3, loopVarName); - MethodInvocation valuesGetter = new MethodInvocation(field3, mapValues); - MethodInvocation callSetter = new MethodInvocation(new Variable(loopVarName), setter.getName(), args); // loopVar.setName2(name2) + EnhancedForStatement broadcastLoop = new EnhancedForStatement(); // for (key2 loopVar: name2Map.keySet()) + String loopVarName = pullEdge.getName() + idPostfix; + keyType = ((MapType) field12.getType()).getKeyType(); + List args = new ArrayList<>(); + args.add(new Variable(loopVarName)); + MethodInvocation valueGetter = new MethodInvocation(field2, mapGet, args); + args = new ArrayList<>(); + args.add(new Variable(loopVarName)); + args.add(valueGetter); + MethodInvocation callSetter = new MethodInvocation(field3, setter.getName(), args); // name3.setName2(loopVar, name2Map.get(loopVar)) Block loopBody = new Block(); loopBody.addStatement(new ExpressionStatement(callSetter)); + VariableDeclaration loopVar = new VariableDeclaration(keyType, loopVarName); + MethodInvocation keysGetter = new MethodInvocation(field2, mapKeySet); broadcastLoop.setParameter(loopVar); - broadcastLoop.setExpression(valuesGetter); + broadcastLoop.setExpression(keysGetter); broadcastLoop.setBody(loopBody); coordionator.addUniqueStatement(broadcastLoop); } } else { VariableDeclaration idVar = new VariableDeclaration(keyType, pushEdge.getName() + idPostfix); coordionator.addParameter(idVar); + List args = new ArrayList<>(); + args.add(new FieldAccess(field12.getName())); ClassInstanceCreation callConstructor = new ClassInstanceCreation((SimpleType) type3.getImplementationType(), args); // new Name3(name2) args = new ArrayList<>(); args.add(new Variable(idVar.getName())); diff --git a/src/main/java/models/dataSynchronizationModel/DataSynchronizationDesign.java b/src/main/java/models/dataSynchronizationModel/DataSynchronizationDesign.java index 8d8b269..7766a54 100644 --- a/src/main/java/models/dataSynchronizationModel/DataSynchronizationDesign.java +++ b/src/main/java/models/dataSynchronizationModel/DataSynchronizationDesign.java @@ -109,6 +109,20 @@ } if (!hasDiagonalRelation) { allRelations.add(transferContext.getSyncronizationRelation().getPrevRelation()); + } else { + Relation lastRelation = allRelations.getLast(); + Relation bottomRelation = null; + if (!transferContext.getSrcObjectHierarchy().isPrefixOf(lastRelation.getSrcObjectHierarchy())) { + bottomRelation = new Relation(transferContext.getSrcObjectHierarchy().getPrevObjectHierarchy(), + transferContext.getSrcObjectHierarchy(), + transferContext.getTransferMultiplicity()); + allRelations.add(bottomRelation); + } else if (!transferContext.getDstObjectHierarchy().isPrefixOf(lastRelation.getDstObjectHierarchy())) { + bottomRelation = new Relation(transferContext.getSrcObjectHierarchy(), + transferContext.getDstObjectHierarchy().getPrevObjectHierarchy(), + transferContext.getTransferMultiplicity()); + allRelations.add(bottomRelation); + } } for (Relation relation: allRelations) { ObjectHierarchy newSrcHierarchy = null; @@ -123,6 +137,7 @@ if ((dstHierarchy == null || dstHierarchy.getDepth() < newDstHierarchy.getDepth()) || (srcHierarchy == null || srcHierarchy.getDepth() < newSrcHierarchy.getDepth())) { List oneDestination = new ArrayList<>(); List manyDestinations = new ArrayList<>(); + boolean nextToOne = toOne; for (int i = 0; i < newDstHierarchy.getDepth(); i++) { if (dstHierarchy != null && i < dstHierarchy.getDepth()) { if (!dstHierarchy.getEdge(i).equals(newDstHierarchy.getEdge(i))) { @@ -130,9 +145,9 @@ } } else { if (newDstHierarchy.getEdge(i).toMany()) { - toOne = false; + nextToOne = false; } - if (toOne) { + if (nextToOne) { oneDestination.add(newDstHierarchy.getEdge(i)); } else { manyDestinations.add(newDstHierarchy.getEdge(i)); @@ -164,7 +179,11 @@ String dataName = dstObj.getName(); dataName = dataName.substring(0, 1).toLowerCase() + dataName.substring(1); if (!prevReference.isIdentical() && !prevReference.getDestination().equals(srcEdge.getDestination())) { - primitiveDeltaList.add(new PrimitivePullPushDelta(prevReference, srcEdge, dataName)); + if (toOne) { + primitiveDeltaList.add(new PrimitivePullPushDelta(prevReference, srcEdge, dataName)); + } else { + primitiveDeltaList.add(new PrimitivePullPushDelta(prevReference, srcEdge, dataName, true)); + } Delta delta = null; for (PrimitiveDelta primDelta : primitiveDeltaList) { if (delta == null) { @@ -179,9 +198,10 @@ prevReference = new ReferenceEdge(srcObj, dstObj, dataName); } } + toOne = nextToOne; if (!toOne) { - boolean multipleDefinition = false; + boolean multipleDefinition = false; // destination multiplicity of the defined reference if ((transferStyle == PushPullValue.PUSH && (relation.getMultiplicity() == MultiplicityValue.ManyToOne || relation.getMultiplicity() == MultiplicityValue.OneToOne)) || (transferStyle != PushPullValue.PUSH && (relation.getMultiplicity() == MultiplicityValue.OneToMany || relation.getMultiplicity() == MultiplicityValue.OneToOne))) { // If the specified multiplicity of destination objects does not match to their potential multiplicity, @@ -192,15 +212,20 @@ // then the reference to select one destination object from potential multiple objects is needed. multipleDefinition = true; } - // 2) Create a component identifying delta. - PrimitiveDelta componentSelectingDelta = null; + // 2) Create a component selecting delta. + PrimitivePullDelta componentSelectingDelta = null; for (ReferenceEdge dstEdge : manyDestinations) { if (componentSelectingDelta == null) { srcObj = (ObjectNode) prevReference.getSource(); dstObj = (ObjectNode) dstEdge.getDestination(); String dataName = dstObj.getName(); dataName = dataName.substring(0, 1).toLowerCase() + dataName.substring(1); - componentSelectingDelta = new PrimitivePullDelta(prevReference, dstEdge, dataName, multipleDefinition); + componentSelectingDelta = new PrimitivePullDelta(prevReference, dstEdge, dataName, multipleDefinition, true); + if (dstObj.equals(transferContext.getSyncronizationRelation().getSrcBottomObject()) + && (transferContext.getSyncronizationRelation().getMultiplicity() == MultiplicityValue.ManyToOne + || transferContext.getSyncronizationRelation().getMultiplicity() == MultiplicityValue.ManyToMany)) { + componentSelectingDelta.setMultipleTransfer(false); + } primitiveDeltaList.add(componentSelectingDelta); Delta delta = null; for (PrimitiveDelta primDelta : primitiveDeltaList) { @@ -212,14 +237,28 @@ } deltaStack.push(delta); // add a component identifying delta primitiveDeltaList.clear(); - prevReference = new ReferenceEdge(srcObj, dstObj, dataName); + if (!multipleDefinition) { + prevReference = new ReferenceEdge(srcObj, dstObj, dataName); + } else { + prevReference = new ReferenceEdge(srcObj, dstObj, dataName, dstEdge.getKeyTypeName()); + } } else { srcObj = (ObjectNode) prevReference.getSource(); dstObj = (ObjectNode) dstEdge.getDestination(); String dataName = dstObj.getName(); dataName = dataName.substring(0, 1).toLowerCase() + dataName.substring(1); - primitiveDeltaList.add(new PrimitivePullDelta(prevReference, dstEdge, dataName, multipleDefinition)); - prevReference = new ReferenceEdge(srcObj, dstObj, dataName); + componentSelectingDelta = new PrimitivePullDelta(prevReference, dstEdge, dataName, multipleDefinition, true); + if (dstObj.equals(transferContext.getSyncronizationRelation().getSrcBottomObject()) + && (transferContext.getSyncronizationRelation().getMultiplicity() == MultiplicityValue.ManyToOne + || transferContext.getSyncronizationRelation().getMultiplicity() == MultiplicityValue.ManyToMany)) { + componentSelectingDelta.setMultipleTransfer(false); + } + primitiveDeltaList.add(componentSelectingDelta); + if (!multipleDefinition) { + prevReference = new ReferenceEdge(srcObj, dstObj, dataName); + } else { + prevReference = new ReferenceEdge(srcObj, dstObj, dataName, dstEdge.getKeyTypeName()); + } } } } diff --git a/src/main/java/models/dataSynchronizationModel/Relation.java b/src/main/java/models/dataSynchronizationModel/Relation.java index b7abb85..5ecfc46 100644 --- a/src/main/java/models/dataSynchronizationModel/Relation.java +++ b/src/main/java/models/dataSynchronizationModel/Relation.java @@ -64,10 +64,18 @@ return srcObjectHierarchy.getTop(); } + public ObjectNode getSrcBottomObject() { + return srcObjectHierarchy.getBottom(); + } + public ObjectNode getDstTopObject() { return dstObjectHierarchy.getTop(); } + public ObjectNode getDstBottomObject() { + return dstObjectHierarchy.getBottom(); + } + public MultiplicityValue getMultiplicity() { return multiplicity; } diff --git a/src/main/java/models/deltaAlgebra/PrimitivePullDelta.java b/src/main/java/models/deltaAlgebra/PrimitivePullDelta.java index bfbbd58..04b7e2f 100644 --- a/src/main/java/models/deltaAlgebra/PrimitivePullDelta.java +++ b/src/main/java/models/deltaAlgebra/PrimitivePullDelta.java @@ -8,6 +8,7 @@ private ReferenceEdge pullEdge1 = null; private ReferenceEdge pullEdge2 = null; private boolean multipleDefinition = false; + private boolean multipleTransfer = false; public PrimitivePullDelta(ReferenceEdge pullEdge1, ReferenceEdge pullEdge2, String dataName) { super(dataName); @@ -22,6 +23,14 @@ this.multipleDefinition = multipleDefinition; } + public PrimitivePullDelta(ReferenceEdge pullEdge1, ReferenceEdge pullEdge2, String dataName, boolean multipleDefinition, boolean multipleTransfer) { + super(dataName); + this.pullEdge1 = pullEdge1; + this.pullEdge2 = pullEdge2; + this.multipleDefinition = multipleDefinition; + this.multipleTransfer = multipleTransfer; + } + @Override public ObjectNode getCoordinator() { return (ObjectNode) pullEdge1.getSource(); @@ -63,9 +72,17 @@ return multipleDefinition; } + public boolean isMultipleTransfer() { + return multipleTransfer; + } + + public void setMultipleTransfer(boolean multipleTransfer) { + this.multipleTransfer = multipleTransfer; + } + @Override public PrimitivePullDelta copy() { - return new PrimitivePullDelta(pullEdge1, pullEdge2, dataName, multipleDefinition); + return new PrimitivePullDelta(pullEdge1, pullEdge2, dataName, multipleDefinition, multipleTransfer); } @Override diff --git a/src/main/java/models/deltaAlgebra/PrimitivePullPushDelta.java b/src/main/java/models/deltaAlgebra/PrimitivePullPushDelta.java index 8fba5de..8c7a95b 100644 --- a/src/main/java/models/deltaAlgebra/PrimitivePullPushDelta.java +++ b/src/main/java/models/deltaAlgebra/PrimitivePullPushDelta.java @@ -8,6 +8,7 @@ private ReferenceEdge pullEdge = null; private ReferenceEdge pushEdge = null; private boolean multipleDefinition = false; + private boolean multipleTransfer = false; public PrimitivePullPushDelta(ReferenceEdge pullEdge, ReferenceEdge pushEdge, String dataName) { super(dataName); @@ -22,6 +23,14 @@ this.multipleDefinition = multipleDefinition; } + public PrimitivePullPushDelta(ReferenceEdge pullEdge, ReferenceEdge pushEdge, String dataName, boolean multipleDefinition, boolean multipleTransfer) { + super(dataName); + this.pullEdge = pullEdge; + this.pushEdge = pushEdge; + this.multipleDefinition = multipleDefinition; + this.multipleTransfer = multipleTransfer; + } + @Override public ObjectNode getCoordinator() { return (ObjectNode) pushEdge.getSource(); @@ -63,9 +72,13 @@ return multipleDefinition; } + public boolean isMultipleTransfer() { + return multipleTransfer; + } + @Override public PrimitivePullPushDelta copy() { - return new PrimitivePullPushDelta(pullEdge, pushEdge, dataName, multipleDefinition); + return new PrimitivePullPushDelta(pullEdge, pushEdge, dataName, multipleDefinition, multipleTransfer); } @Override