diff --git a/models/designPattern/MediatorInsertionTest.Json b/models/designPattern/MediatorInsertionTest.Json index d8a0ac9..5313cbe 100644 --- a/models/designPattern/MediatorInsertionTest.Json +++ b/models/designPattern/MediatorInsertionTest.Json @@ -6,7 +6,7 @@ "transfer": { "src": "A", "dst": "B", - "data": { "type": "String", "name": "data" }, + "data": { "type": "String", "name": "string" }, "style": "PUSH", "multiplicity": "1:1" } diff --git a/src/main/java/designPatternExtensions/ControlFlowInversion.java b/src/main/java/designPatternExtensions/ControlFlowInversion.java deleted file mode 100644 index 59880dd..0000000 --- a/src/main/java/designPatternExtensions/ControlFlowInversion.java +++ /dev/null @@ -1,22 +0,0 @@ -package designPatternExtensions; - -import models.objectOrientedTransfer.PushPullValue; - -public class ControlFlowInversion { - private MediatorInsertion mediatorInsertion; - private PushPullValue newDirection; - - public ControlFlowInversion(MediatorInsertion mediatorInsertion, PushPullValue newDirection){ - this.mediatorInsertion = mediatorInsertion; - this.newDirection = newDirection; - } - - public MediatorInsertion getMediatorInsertion(){ - return mediatorInsertion; - } - - public PushPullValue getNewDirection(){ - return newDirection; - } - -} diff --git a/src/main/java/designPatternExtensions/MediatorInsertion.java b/src/main/java/designPatternExtensions/MediatorInsertion.java index 6a2b7a6..2ccd7bb 100644 --- a/src/main/java/designPatternExtensions/MediatorInsertion.java +++ b/src/main/java/designPatternExtensions/MediatorInsertion.java @@ -1,23 +1,28 @@ package designPatternExtensions; -import designPatternExtensions.designPattern.MediatorInsertionTest; import models.objectOrientedTransfer.DataTransferContext; -import models.objectOrientedTransfer.DataTransferDesign; import models.objectOrientedTransfer.ObjectNode; - -import javax.print.attribute.standard.Media; +import models.objectOrientedTransfer.PushPullValue; public class MediatorInsertion { private ObjectNode src; private ObjectNode dst; private ObjectNode mediator; - private DataTransferContext context; + private PushPullValue pushPullValue; + //全デザインパターンに適応出来たら不要になるメソッド public MediatorInsertion(ObjectNode src, ObjectNode dst, ObjectNode mediator, DataTransferContext context) { this.src = src; this.dst = dst; this.mediator = mediator; - this.context = context; + this.pushPullValue = context.getTransferStyle(); + } + + public MediatorInsertion(ObjectNode src, ObjectNode dst, ObjectNode mediator, PushPullValue pushPullValue) { + this.src = src; + this.dst = dst; + this.mediator = mediator; + this.pushPullValue = pushPullValue; } public ObjectNode getSrc() { @@ -32,7 +37,7 @@ return mediator; } - public DataTransferContext getContext() { - return context; + public PushPullValue getPushPullValue() { + return pushPullValue; } } \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/PresenterInsertion.java b/src/main/java/designPatternExtensions/PresenterInsertion.java new file mode 100644 index 0000000..4957343 --- /dev/null +++ b/src/main/java/designPatternExtensions/PresenterInsertion.java @@ -0,0 +1,33 @@ +package designPatternExtensions; + +import models.objectOrientedTransfer.ObjectNode; +import models.objectOrientedTransfer.PushPullValue; + +public class PresenterInsertion { + private ObjectNode src; + private ObjectNode dst; + private ObjectNode presenter; + private PushPullValue pushPullValue; + + public PresenterInsertion(ObjectNode src, ObjectNode dst, ObjectNode presenter, PushPullValue pushPullValue) { + this.src = src; + this.dst = dst; + this.presenter = presenter; + this.pushPullValue = pushPullValue; + } + + public ObjectNode getSrc() { + return src; + } + + public ObjectNode getDst() { + return dst; + } + + public ObjectNode getPresenter() { + return presenter; + } + + public PushPullValue getPushPullValue() { return pushPullValue; } + +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Builder.java b/src/main/java/designPatternExtensions/designPattern/Builder.java index 06b2805..009332a 100644 --- a/src/main/java/designPatternExtensions/designPattern/Builder.java +++ b/src/main/java/designPatternExtensions/designPattern/Builder.java @@ -1,6 +1,7 @@ package designPatternExtensions.designPattern; import designPatternExtensions.MediatorInsertion; +import designPatternExtensions.PresenterInsertion; import models.objectOrientedTransfer.*; import designPatternExtensions.ModelLoader; @@ -16,12 +17,16 @@ public DataTransferDesign create() throws IllegalRelationException { DataTransferDesign design = ModelLoader.load("models/designPattern/Builder.Json"); - ObjectNode builder = design.getTransferContexts().getFirst().getSrcFirstResource(); - ObjectNode main = design.getTransferContexts().getFirst().getDstFirstResource(); + DataTransferContext dtc = design.getTransferContexts().getFirst(); + ObjectNode builder = dtc.getSrcFirstResource(); + ObjectNode main = dtc.getDstFirstResource(); // // MediatorInsertion mi = new MediatorInsertion(main, builder, new ObjectNode("Hero")); // design.addMediatorInsertion(mi); + PresenterInsertion pi = new PresenterInsertion(main, builder, new ObjectNode("Presenter"), dtc.getTransferStyle()); + design.addPresenterInsertion(pi); + return design; } } \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/MediatorInsertionTest.java b/src/main/java/designPatternExtensions/designPattern/MediatorInsertionTest.java index 3f0e6dc..3a973ed 100644 --- a/src/main/java/designPatternExtensions/designPattern/MediatorInsertionTest.java +++ b/src/main/java/designPatternExtensions/designPattern/MediatorInsertionTest.java @@ -11,20 +11,27 @@ DataTransferContext dtc = design.getTransferContexts().getFirst(); ObjectNode a = dtc.getSrcFirstResource(); ObjectNode b = dtc.getDstFirstResource(); +// +// ObjectNode me = new ObjectNode("Me"); +// MediatorInsertion mi = new MediatorInsertion(a, b, me, dtc.getTransferStyle()); +// design.addMediatorInsertion(mi); - ObjectNode me = new ObjectNode("Me"); - MediatorInsertion mi = new MediatorInsertion(a, b, me, dtc); - design.addMediatorInsertion(mi); - // ControlFlowInversion ci = new ControlFlowInversion(mi, PushPullValue.PUSH); + ObjectNode presenter = new ObjectNode("Presenter"); + PresenterInsertion pi = new PresenterInsertion(a, b, presenter, dtc.getTransferStyle()); + design.addPresenterInsertion(pi); return design; } } + +//A側Mediatorのsetter作成 + +//PresenterのSetDataをupdateDataとして命名されるように + //Contextを持たせる理由 //DataTransferDesignにはContextのリストがあり、その時に、いずれかのコンテキストのデータ転送かを //判別する必要があると思うので、それを区別するためにMediatorInsertionの引数に渡している -// A -PUSH-> B にMediatorInsertionする場合はnew MediatorInsertion(A, B, me); -// A -PULL-> B の時はnew MediatorInsertion(B, A, me); -// Meが主導に時はPULL->PUSHになる? \ No newline at end of file +// Meが主導に時はPULL->PUSHになる -> PresenterInsertion or ControllerInsertionとして扱い +//PULLPULL PUSHPUSHはMediatorInsertionとして扱う \ No newline at end of file diff --git a/src/main/java/generators/ASTGenerator.java b/src/main/java/generators/ASTGenerator.java index 3cd6291..89f5709 100644 --- a/src/main/java/generators/ASTGenerator.java +++ b/src/main/java/generators/ASTGenerator.java @@ -7,6 +7,7 @@ import designPatternExtensions.DependencyInversion; import designPatternExtensions.InterfaceNode; import designPatternExtensions.MediatorInsertion; +import designPatternExtensions.PresenterInsertion; import models.algebra.Type; import models.dataConstraintModel.MapType; import models.objectOrientedTransfer.*; @@ -38,6 +39,9 @@ for (MediatorInsertion mi: dataTransferDesign.getMediatorInsertions()) { codebase = weaveMediatorInsertion(codebase, mi); } + for (PresenterInsertion pi: dataTransferDesign.getPresenterInsertions()) { + codebase = weavePresenterInsertion(codebase, pi); + } for (DependencyInversion di: dataTransferDesign.getDependencyInversions()) { codebase = weaveDependencyInversion(codebase, di); } @@ -235,8 +239,9 @@ return codebase; } + public static Codebase weaveMediatorInsertion(Codebase codebase, MediatorInsertion mediatorInsertion) { - PushPullValue style = mediatorInsertion.getContext().getTransferStyle(); + PushPullValue style = mediatorInsertion.getPushPullValue(); ObjectNode srcNode, dstNode; if (style == PushPullValue.PUSH) { srcNode = mediatorInsertion.getSrc(); @@ -259,7 +264,6 @@ models.algebra.Type mediatorType = codebase.getComponentType(mediatorName); FieldDeclaration dstField = createField(mediatorClass, dstFieldName, dstType); - // Add Constructor MethodDeclaration constructor = createConstructor(mediatorClass); VariableDeclaration dstParam = new VariableDeclaration(dstType, dstFieldName); @@ -307,6 +311,14 @@ } } + // Add Mediator Setter + MethodDeclaration mediatorSetter = createMethod(srcClass, setterPrefix + mediatorName); + VariableDeclaration mediatorParam = new VariableDeclaration(mediatorType, mediatorFieldName); + mediatorSetter.addParameter(mediatorParam); + FieldAccess mediatorFieldAccess = new FieldAccess(new ThisExpression(), mediatorFieldName); + Assignment mediatorAssignment = new Assignment(mediatorFieldAccess, new Variable(mediatorFieldName)); // this.me = me; + mediatorSetter.addStatement(new ExpressionStatement(mediatorAssignment)); + // Change the constructor parameter type in src from dst to Mediator, and rename the parameter accordingly for (MethodDeclaration method: srcClass.getMethods()) { if (method.isConstructor() && method.getParameters() != null) { @@ -386,6 +398,169 @@ } } + + public static Codebase weavePresenterInsertion(Codebase codebase, PresenterInsertion presenterInsertion) { + ObjectNode srcNode = presenterInsertion.getSrc(); + ObjectNode dstNode = presenterInsertion.getDst(); + ObjectNode presenterNode = presenterInsertion.getPresenter(); + String srcName = toComponentName(srcNode.getName()); + String dstName = toComponentName(dstNode.getName()); + String presenterName = toComponentName(presenterNode.getName()); + String srcFieldName = toVariableName(srcName); + String dstFieldName = toVariableName(dstName); + + models.algebra.Type srcType = codebase.getComponentType(srcName); + models.algebra.Type dstType = codebase.getComponentType(dstName); + + TypeDeclaration presenterClass = createClass(codebase, presenterName); + + FieldDeclaration srcField = createField(presenterClass, srcFieldName, srcType); + FieldDeclaration dstField = createField(presenterClass, dstFieldName, dstType); + + MethodDeclaration constructor = createConstructor(presenterClass); + VariableDeclaration srcParam = new VariableDeclaration(srcType, srcFieldName); + VariableDeclaration dstParam = new VariableDeclaration(dstType, dstFieldName); + constructor.addParameter(srcParam); + constructor.addParameter(dstParam); + constructor.addStatement(new ExpressionStatement( + new Assignment(new FieldAccess(new ThisExpression(), srcField.getName()), new Variable(srcFieldName)))); + constructor.addStatement(new ExpressionStatement( + new Assignment(new FieldAccess(new ThisExpression(), dstField.getName()), new Variable(dstFieldName)))); + + TypeDeclaration srcClass = createClass(codebase, srcName); + TypeDeclaration dstClass = createClass(codebase, dstName); + + List getters = new ArrayList<>(); + List boundProperties = new ArrayList<>(); + + for (MethodDeclaration getter: srcClass.getMethods()) { + if (getter.isConstructor() || getter.getReturnType() == null) continue; + if (!getter.getName().startsWith(getterPrefix)) continue; + getters.add(getter); + boundProperties.add(getter.getName().substring(getterPrefix.length())); + } + + for (FieldDeclaration field: srcClass.getFields()) { + if (field.getType() == null) continue; + if (field.getType().getTypeName().equals(dstType.getTypeName())) continue; // navigation field toward dst, not data + String propertyName = toComponentName(field.getName()); + if (boundProperties.contains(propertyName)) continue; // already exposed via an existing getter above + + MethodDeclaration newGetter = createMethod(srcClass, getterPrefix + propertyName); + if (newGetter.getReturnType() == null) { + + ReturnStatement returnStatement = new ReturnStatement(); + returnStatement.setExpression(new FieldAccess(new ThisExpression(), field.getName())); + newGetter.addStatement(returnStatement); + newGetter.setReturnType(field.getType()); + } + getters.add(newGetter); + boundProperties.add(propertyName); + } + + for (MethodDeclaration getter: getters) { + //Derive the setter name from the getter's type name + String propertyName = getter.getName().substring(getterPrefix.length()); + String setterName = setterPrefix + propertyName; + + // Create a new setter if dstClass does not have one + MethodDeclaration setter = createMethod(dstClass, setterName); + if (setter.getReturnType() == null && (setter.getParameters() == null || setter.getParameters().isEmpty())) { + // Build the setter body only when a new setter is created + models.algebra.Type propertyType = getter.getReturnType(); + VariableDeclaration setterParam = new VariableDeclaration(propertyType, toVariableName(propertyName)); + setter.addParameter(setterParam); + // Find the corresponding field in dstClass, or create one if it doesn't exist + FieldDeclaration propertyField = createField(dstClass, toVariableName(propertyName), propertyType); + setter.addStatement(new ExpressionStatement( + new Assignment(new FieldAccess(new ThisExpression(), propertyField.getName()), new Variable(toVariableName(propertyName))))); + } + + // Add the binding method to the Presenter + String presenterMethodName = updateMethodPrefix + propertyName; + MethodDeclaration coordinator = createMethod(presenterClass, presenterMethodName); + List getterArgs = new ArrayList<>(); + MethodInvocation callGetter = new MethodInvocation(new FieldAccess(srcField.getName()), getter.getName(), getterArgs); + List setterArgs = new ArrayList<>(); + setterArgs.add(callGetter); + MethodInvocation callSetter = new MethodInvocation(new FieldAccess(dstField.getName()), setter.getName(), setterArgs); + coordinator.addStatement(new ExpressionStatement(callSetter)); + } + + removeDirectDependency(srcClass, dstType); + removeDirectDependency(dstClass, srcType); + + return codebase; + } + + private static void removeDirectDependency(TypeDeclaration typeDecl, models.algebra.Type otherType) { + List fieldsToRemove = new ArrayList<>(); + for (FieldDeclaration field: typeDecl.getFields()) { + if (field.getType() != null && field.getType().getTypeName().equals(otherType.getTypeName())) { + fieldsToRemove.add(field); + } + } + if (fieldsToRemove.isEmpty()) return; + + List methodsToRemove = new ArrayList<>(); + for (MethodDeclaration method: typeDecl.getMethods()) { + if (method.isConstructor()) continue; + for (FieldDeclaration field: fieldsToRemove) { + if (methodReferencesField(method, field.getName())) { + methodsToRemove.add(method); + break; + } + } + } + for (MethodDeclaration method: methodsToRemove) { + typeDecl.removeMethod(method); + } + for (FieldDeclaration field: fieldsToRemove) { + typeDecl.removeField(field); + } + } + + private static boolean methodReferencesField(MethodDeclaration method, String fieldName) { + if (method.getBody() == null) return false; + for (Statement statement: method.getBody().getStatements2()) { + if (statementReferencesField(statement, fieldName)) return true; + } + return false; + } + + private static boolean statementReferencesField(Statement statement, String fieldName) { + if (statement instanceof ExpressionStatement) { + return expressionReferencesField(((ExpressionStatement) statement).getExpression(), fieldName); + } else if (statement instanceof ReturnStatement) { + Expression expr = ((ReturnStatement) statement).getExpression(); + return expr != null && expressionReferencesField(expr, fieldName); + } + return false; + } + + private static boolean expressionReferencesField(Expression expr, String fieldName) { + if (expr == null) return false; + if (expr instanceof FieldAccess) { + FieldAccess fa = (FieldAccess) expr; + if (fieldName.equals(fa.getFieldName())) return true; + } + if (expr instanceof MethodInvocation) { + MethodInvocation mi = (MethodInvocation) expr; + if (expressionReferencesField(mi.getReceiver(), fieldName)) return true; + if (mi.getArguments() != null) { + for (Expression arg: mi.getArguments()) { + if (expressionReferencesField(arg, fieldName)) return true; + } + } + } else if (expr instanceof Assignment) { + Assignment assignment = (Assignment) expr; + if (expressionReferencesField(assignment.getLeft(), fieldName)) return true; + if (expressionReferencesField(assignment.getRight(), fieldName)) return true; + } + return false; + } + + public static Codebase weaveDependencyInversion(Codebase codebase, DependencyInversion dependencyInversion) { ObjectNode dstNode = dependencyInversion.getDst(); InterfaceNode interfaceNode = dependencyInversion.getInterfaceNode(); @@ -498,7 +673,7 @@ for (MethodDeclaration method: type.getMethods()) { if (method.getName().equals(type.getTypeName())) return method; } - MethodDeclaration method = new MethodDeclaration(type.getTypeName(), true); // constructor + MethodDeclaration method = new MethodDeclaration(type.getTypeName(), true); type.addMethod(method); return method; } diff --git a/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java b/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java index e05cac9..9aa7fc8 100644 --- a/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java +++ b/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java @@ -3,6 +3,7 @@ import designPatternExtensions.DependencyInversion; import designPatternExtensions.MediatorInsertion; +import designPatternExtensions.PresenterInsertion; import parser.*; import parser.exceptions.ExpectedJsonValue; @@ -21,6 +22,7 @@ private DeltaComplex deltaComplex; private List dependencyInversions = new ArrayList<>(); private List mediatorInsertions = new ArrayList<>(); + private List presenterInsertions = new ArrayList<>(); public DataTransferDesign(DataTransferContext transferContext) throws IllegalRelationException { this.transferContexts = new ArrayList<>(); @@ -55,6 +57,14 @@ return mediatorInsertions; } + public void addPresenterInsertion(PresenterInsertion presenterInsertion) { + presenterInsertions.add(presenterInsertion); + } + + public List getPresenterInsertions() { + return presenterInsertions; + } + public DeltaComplex createDefaultDeltaComlex(DataTransferContext transferContext) throws IllegalRelationException { if (transferContext.getTransferStyle() == PushPullValue.PUSH) { // PUSH transfer