diff --git a/models/designPattern/AbstractFactory.Json b/models/designPattern/AbstractFactory.Json new file mode 100644 index 0000000..6007b64 --- /dev/null +++ b/models/designPattern/AbstractFactory.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "ConcreteCastle", + "dst": "App", + "data": { "type": "String", "name": "description" }, + "style": "PULL", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Adapter.Json b/models/designPattern/Adapter.Json new file mode 100644 index 0000000..9cb8afd --- /dev/null +++ b/models/designPattern/Adapter.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "FishingBoat", + "dst": "Captain", + "data": { "type": "String", "name": "data" }, + "style": "PULL", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Bridge.Json b/models/designPattern/Bridge.Json new file mode 100644 index 0000000..bfab65f --- /dev/null +++ b/models/designPattern/Bridge.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "ConcreteEnchantment", + "dst": "ConcreteWeapon", + "data": { "type": "String", "name": "data" }, + "style": "PULL", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Builder.Json b/models/designPattern/Builder.Json new file mode 100644 index 0000000..0ba1d34 --- /dev/null +++ b/models/designPattern/Builder.Json @@ -0,0 +1,44 @@ +{ + "name" : "Builder", + "contexts" : [ + { + "relations": [], + "transfer": { + "src": "Builders.{Builder}", + "dst": "Heroes.{Hero}", + "data": { + "type": "HairType", + "name": "hairType" + }, + "style": "PUSH", + "multiplicity": "1:1" + } + }, + { + "relations": [], + "transfer": { + "src": "Builders.{Builder}", + "dst": "Heroes.{Hero}", + "data": { + "type": "HairColor", + "name": "hairColor" + }, + "style": "PUSH", + "multiplicity": "1:1" + } + }, + { + "relations": [], + "transfer": { + "src": "Builders.{Builder}", + "dst": "Heroes.{Hero}", + "data": { + "type": "Armor", + "name": "armor" + }, + "style": "PUSH", + "multiplicity": "1:1" + } + } + ] +} \ No newline at end of file diff --git a/models/designPattern/Command.Json b/models/designPattern/Command.Json new file mode 100644 index 0000000..f0641c9 --- /dev/null +++ b/models/designPattern/Command.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "Wizard.{Stack}", + "dst": "Goblin.Size", + "data": { "type": "String", "name": "data" }, + "style": "PUSH", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Decorator.Json b/models/designPattern/Decorator.Json new file mode 100644 index 0000000..76fd619 --- /dev/null +++ b/models/designPattern/Decorator.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "SimpleTroll", + "dst": "Client", + "data": { "type": "String", "name": "data" }, + "style": "PULL", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Iterator.Json b/models/designPattern/Iterator.Json new file mode 100644 index 0000000..5997071 --- /dev/null +++ b/models/designPattern/Iterator.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "TreasureChest", + "dst": "Client", + "data": { "type": "String", "name": "data" }, + "style": "PULL", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Proxy.Json b/models/designPattern/Proxy.Json new file mode 100644 index 0000000..5b9af0b --- /dev/null +++ b/models/designPattern/Proxy.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "Client", + "dst": "IvoryTower", + "data": { "type": "Wizard", "name": "wizard" }, + "style": "PUSH", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/State.Json b/models/designPattern/State.Json new file mode 100644 index 0000000..7fa778b --- /dev/null +++ b/models/designPattern/State.Json @@ -0,0 +1,24 @@ +{ + "name" : "State", + "contexts" : [ + { + "relations": [ + { + "src" : "Main.Mammoth", + "dst" : "Main.Mammoth.{ConcreteState}", + "multiplicity" : "1:1" + } + ], + "transfer": { + "src": "Main.Mammoth.{ConcreteState}", + "dst": "Main", + "data": { + "type": "String", + "name": "data" + }, + "style": "PUSH", + "multiplicity": "1:1" + } + } + ] +} \ No newline at end of file diff --git a/models/designPattern/Strategy.Json b/models/designPattern/Strategy.Json new file mode 100644 index 0000000..9d70b0a --- /dev/null +++ b/models/designPattern/Strategy.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "main.dragonSlayer", + "dst": "main.{ConcreteStrategy}", + "data": { "type": "String", "name": "data" }, + "style": "PUSH", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/models/designPattern/Visitor@Editing.Json b/models/designPattern/Visitor@Editing.Json new file mode 100644 index 0000000..88ccd09 --- /dev/null +++ b/models/designPattern/Visitor@Editing.Json @@ -0,0 +1,10 @@ +{ + "relations": [], + "transfer": { + "src": "", + "dst": "", + "data": { "type": "String", "name": "visitor" }, + "style": "PULL", + "multiplicity": "1:1" + } +} \ No newline at end of file diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 0040c85..f97ac6f 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -1,6 +1,8 @@ import java.util.ArrayList; import java.util.List; +import designPatternExtensions.*; +import designPatternExtensions.designPattern.Adapter; import generators.ASTGenerator; import models.objectOrientedTransfer.*; @@ -20,16 +22,25 @@ dstEdges.add(dstEdge); List relations = new ArrayList<>(); // Relation transferRelation = new Relation(company, customer, MultiplicityValue.OneToOne); - Relation transferRelation = new Relation(srcEdges, dstEdges, MultiplicityValue.OneToMany); - DataTransferContext context = new DataTransferContext(relations, transferRelation, address, "address", PushPullValue.PULL); + Relation transferRelation = new Relation(srcEdges, dstEdges, MultiplicityValue.OneToMany); + DataTransferContext context = new DataTransferContext(relations, transferRelation, address, "address", PushPullValue.PUSH); + + DataTransferDesign design; + try { + design = new DataTransferDesign(context); - DataTransferDesign design; - try { - design = new DataTransferDesign(context); - System.out.println(ASTGenerator.generate(design)); - } catch (IllegalRelationException e) { - e.printStackTrace(); - } - } + ObjectNode cm = new ObjectNode("CompanyMediator"); + MediatorInsertion mi = new MediatorInsertion(customer, company, cm); + design.addMediatorInsertion(mi); + + DependencyInversion di = new DependencyInversion(company, new InterfaceNode(company, "ICompany"), customer); + design.addDependencyInversion(di); + + System.out.println(ASTGenerator.generate(design)); + } catch (IllegalRelationException e) { + e.printStackTrace(); + } + + } } diff --git a/src/main/java/ast/CompilationUnit.java b/src/main/java/ast/CompilationUnit.java index 68403a1..f4af142 100644 --- a/src/main/java/ast/CompilationUnit.java +++ b/src/main/java/ast/CompilationUnit.java @@ -7,15 +7,21 @@ private String fileName = null; private List imports = new ArrayList<>(); private List types = new ArrayList<>(); - + private List interfaces = new ArrayList<>(); + public CompilationUnit(TypeDeclaration type) { types.add(type); - if(type.getTypeName().contains("<")) + if(type.getTypeName().contains("<")) fileName = type.getTypeName().split("<")[0] + ".java"; else fileName = type.getTypeName() + ".java"; } - + + public CompilationUnit(InterfaceDeclaration interfaceDeclaration) { + interfaces.add(interfaceDeclaration); + fileName = interfaceDeclaration.getTypeName() + ".java"; + } + public List imports() { return imports; } @@ -32,6 +38,14 @@ types.add(type); } + public List interfaces() { + return interfaces; + } + + public void addInterface(InterfaceDeclaration interfaceDeclaration) { + interfaces.add(interfaceDeclaration); + } + public String getFileName() { return fileName; } @@ -45,6 +59,9 @@ for (TypeDeclaration type: types) { result += type.toString(); } + for (InterfaceDeclaration iDec: interfaces) { + result += iDec.toString(); + } return result; } -} +} \ No newline at end of file diff --git a/src/main/java/ast/InterfaceDeclaration.java b/src/main/java/ast/InterfaceDeclaration.java new file mode 100644 index 0000000..61de92d --- /dev/null +++ b/src/main/java/ast/InterfaceDeclaration.java @@ -0,0 +1,71 @@ +package ast; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class InterfaceDeclaration extends AbstractTypeDeclaration implements IAnnotatable { + private List methods = new ArrayList<>(); + private Map annotations = new HashMap<>(); + + public InterfaceDeclaration(String typeName) { + this.typeName = typeName; + } + + public void addMethod(MethodDeclaration method) { + methods.add(method); + } + + public void removeMethod(MethodDeclaration method) { + methods.remove(method); + } + + public List getMethods() { + return methods; + } + + @Override + public Annotation getAnnotation(String name) { + return annotations.get(name); + } + + @Override + public Collection getAnnotations() { + return annotations.values(); + } + + @Override + public void addAnnotation(Annotation annotation) { + annotations.put(annotation.getElementName(), annotation); + } + + public String toString() { + String code = ""; + for (Annotation annotation : getAnnotations()) { + code += annotation.toString() + "\n"; + } + code += "public interface " + typeName + " {\n"; + for (MethodDeclaration m : methods) { + String signature = "\t"; + if (m.getReturnType() == null) { + signature += "void "; + } else { + signature += m.getReturnType().getInterfaceTypeName() + " "; + } + signature += m.getName() + "("; + if (m.getParameters() != null) { + for (int i = 0; i < m.getParameters().size(); i++) { + signature += m.getParameters().get(i).toString(); + if (i < m.getParameters().size() - 1) signature += ", "; + } + } + signature += ");\n"; + code += signature; + } + code += "}"; + return code; + } +} \ No newline at end of file diff --git a/src/main/java/ast/TypeDeclaration.java b/src/main/java/ast/TypeDeclaration.java index 4d4a3e5..ceda7a6 100644 --- a/src/main/java/ast/TypeDeclaration.java +++ b/src/main/java/ast/TypeDeclaration.java @@ -10,7 +10,8 @@ private List fields = new ArrayList<>(); private List methods = new ArrayList<>(); private Map annotations = new HashMap<>(); - + private List implementsInterfaces = new ArrayList<>(); + public TypeDeclaration(String typeName) { this.typeName = typeName; } @@ -25,7 +26,15 @@ this.fields = fields; this.methods = methods; } - + + public void addImplementsInterface(String interfaceName) { + implementsInterfaces.add(interfaceName); + } + + public List getImplementsInterfaces() { + return implementsInterfaces; + } + public void addField(FieldDeclaration field) { fields.add(field); } @@ -38,6 +47,10 @@ methods.remove(method); } + public void removeField(FieldDeclaration field) { + fields.remove(field); + } + public List getFields() { return fields; } @@ -72,7 +85,11 @@ for (Annotation annotation: getAnnotations()) { code += annotation.toString() + "\n"; } - code += "public class " + typeName + " {\n"; + code += "public class " + typeName; + if (!implementsInterfaces.isEmpty()) { + code += " implements " + String.join(", ", implementsInterfaces); + } + code += " {\n"; for (FieldDeclaration f: fields) { code += "\t" + f.toString(); } diff --git a/src/main/java/designPatternExtensions/DependencyInversion.java b/src/main/java/designPatternExtensions/DependencyInversion.java new file mode 100644 index 0000000..e007a9d --- /dev/null +++ b/src/main/java/designPatternExtensions/DependencyInversion.java @@ -0,0 +1,35 @@ +package designPatternExtensions; + +import models.objectOrientedTransfer.ObjectNode; + +public class DependencyInversion { + private ObjectNode dst; + private InterfaceNode interfaceNode; + private ObjectNode targetSrc; + + // Reverse all dependencies to the destination ObjectNode + public DependencyInversion(ObjectNode dst, InterfaceNode interfaceNode) { + this.dst = dst; + this.interfaceNode = interfaceNode; + this.targetSrc = null; + } + + // Reverse the dependency for a single ObjectNode + public DependencyInversion(ObjectNode dst, InterfaceNode interfaceNode, ObjectNode targetSrc) { + this.dst = dst; + this.interfaceNode = interfaceNode; + this.targetSrc = targetSrc; + } + + public ObjectNode getDst() { + return dst; + } + + public InterfaceNode getInterfaceNode() { + return interfaceNode; + } + + public ObjectNode getTargetSrc() { + return targetSrc; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/InterfaceNode.java b/src/main/java/designPatternExtensions/InterfaceNode.java new file mode 100644 index 0000000..cf8facd --- /dev/null +++ b/src/main/java/designPatternExtensions/InterfaceNode.java @@ -0,0 +1,38 @@ +package designPatternExtensions; + +import models.objectOrientedTransfer.ObjectNode; + +import java.util.HashSet; +import java.util.Set; + +public class InterfaceNode extends ObjectNode { + private Set dependencySideNodes = new HashSet<>(); + private ObjectNode implementSideNode = null; + + public InterfaceNode(ObjectNode implementSideNode, String name) { + super(name); + this.implementSideNode = implementSideNode; + } + + public InterfaceNode(ObjectNode dependencySideNode, ObjectNode implementSideNode, String name) { + super(name); + this.dependencySideNodes.add(dependencySideNode); + this.implementSideNode = implementSideNode; + } + + public Set getDependencySideNodes() { + return dependencySideNodes; + } + + public void addDependencySideNode(ObjectNode node) { + dependencySideNodes.add(node); + } + + public ObjectNode getImplementSideNode() { + return implementSideNode; + } + + public void setImplementSideNode(ObjectNode implementSideNode) { + this.implementSideNode = implementSideNode; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/MediatorInsertion.java b/src/main/java/designPatternExtensions/MediatorInsertion.java new file mode 100644 index 0000000..552a090 --- /dev/null +++ b/src/main/java/designPatternExtensions/MediatorInsertion.java @@ -0,0 +1,40 @@ +package designPatternExtensions; + +import models.objectOrientedTransfer.ObjectNode; + +public class MediatorInsertion { + private ObjectNode src; + private ObjectNode dst; + private ObjectNode mediator; + private String mediatorFieldName; + + public MediatorInsertion(ObjectNode src, ObjectNode dst, ObjectNode mediator) { + this.src = src; + this.dst = dst; + this.mediator = mediator; + this.mediatorFieldName = mediator.getName().substring(0, 1).toLowerCase() + mediator.getName().substring(1); + } + + public MediatorInsertion(ObjectNode src, ObjectNode dst, ObjectNode mediator, String mediatorFieldName) { + this.src = src; + this.dst = dst; + this.mediator = mediator; + this.mediatorFieldName = mediatorFieldName; + } + + public ObjectNode getSrc() { + return src; + } + + public ObjectNode getDst() { + return dst; + } + + public ObjectNode getMediator() { + return mediator; + } + + public String getMediatorFieldName() { + return mediatorFieldName; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/ModelLoader.java b/src/main/java/designPatternExtensions/ModelLoader.java new file mode 100644 index 0000000..122b264 --- /dev/null +++ b/src/main/java/designPatternExtensions/ModelLoader.java @@ -0,0 +1,50 @@ +package designPatternExtensions; + +import models.objectOrientedTransfer.DataTransferContext; +import models.objectOrientedTransfer.DataTransferDesign; +import models.objectOrientedTransfer.IllegalRelationException; +import parser.JsonValue; +import parser.Parser; +import parser.Value; +import parser.exceptions.ExpectedArrayValue; +import parser.exceptions.ExpectedJsonValue; +import parser.exceptions.ExpectedStringValue; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; + +public class ModelLoader { + + public static DataTransferDesign load(String path) { + File file = new File(path); + try { + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + Value jsonValue = parser.getValue(); + DataTransferDesign design; + return new DataTransferDesign((JsonValue) jsonValue); + + } catch (java.io.FileNotFoundException | ExpectedArrayValue + | ExpectedStringValue | ExpectedJsonValue e) { + throw new RuntimeException("Failed to load model: " + path, e); + } catch (IllegalRelationException e) { + throw new RuntimeException(e); + } + } + + public static DataTransferDesign load2(String path) { + File file = new File(path); + try { + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + Value jsonValue = parser.getValue(); + DataTransferContext context = new DataTransferContext(jsonValue); + return new DataTransferDesign(context); + + } catch (java.io.FileNotFoundException | ExpectedArrayValue + | ExpectedStringValue | ExpectedJsonValue e) { + throw new RuntimeException("Failed to load model: " + path, e); + } catch (IllegalRelationException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/AbstractFactory.java b/src/main/java/designPatternExtensions/designPattern/AbstractFactory.java new file mode 100644 index 0000000..f8f6aad --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/AbstractFactory.java @@ -0,0 +1,31 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.*; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +//https://github.com/iluwatar/java-design-patterns/tree/master/abstract-factory +//App -> ConcreteKingdomFactory -> ConcreteCastle + +public class AbstractFactory implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/AbstractFactory.Json"); + ObjectNode concreteCastle = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode app = design.getTransferContexts().getFirst().getDstFirstResource(); + + ObjectNode concreteKingdomFactory = new ObjectNode("ConcreteKingdomFactory"); + MediatorInsertion mi = new MediatorInsertion(app, concreteCastle, concreteKingdomFactory); + design.addMediatorInsertion(mi); + + DependencyInversion di1 = new DependencyInversion( + concreteKingdomFactory, new InterfaceNode(concreteKingdomFactory, "KingdomFactory")); + design.addDependencyInversion(di1); + + DependencyInversion di2 = new DependencyInversion( + concreteCastle, new InterfaceNode(concreteCastle, "Castle")); + design.addDependencyInversion(di2); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Adapter.java b/src/main/java/designPatternExtensions/designPattern/Adapter.java new file mode 100644 index 0000000..a329820 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Adapter.java @@ -0,0 +1,26 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +public class Adapter implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/Adapter.Json"); + ObjectNode fishingBoat = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode captain = design.getTransferContexts().getFirst().getDstFirstResource(); + + ObjectNode adapter = new ObjectNode("FishingBoatAdapter"); + MediatorInsertion mi = new MediatorInsertion(captain, fishingBoat, adapter); + design.addMediatorInsertion(mi); + + DependencyInversion di = new DependencyInversion( + adapter, new InterfaceNode(adapter, "RowingBoat")); + design.addDependencyInversion(di); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Bridge.java b/src/main/java/designPatternExtensions/designPattern/Bridge.java new file mode 100644 index 0000000..ed9f29b --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Bridge.java @@ -0,0 +1,28 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +import java.util.ArrayList; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/bridge + +public class Bridge implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/"+this.getClass().getSimpleName()+".Json"); + ObjectNode concreteEnchant = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode concreteWeapon = design.getTransferContexts().getFirst().getDstFirstResource(); + + DependencyInversion di1 = new DependencyInversion(concreteWeapon, new InterfaceNode(concreteWeapon, "Weapon")); + design.addDependencyInversion(di1); + + DependencyInversion di2 = new DependencyInversion(concreteEnchant, new InterfaceNode(concreteEnchant, "Enchantment")); + design.addDependencyInversion(di2); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Builder.java b/src/main/java/designPatternExtensions/designPattern/Builder.java new file mode 100644 index 0000000..06b2805 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Builder.java @@ -0,0 +1,27 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +import java.util.ArrayList; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/builder +//staticがないとnew Hero().new Builder(...)のような形になり、Builderとして成立しない +//なんならメソッドチェーンもない +//Mainが仲介者になり、制御の委譲を用いる必要がある + +public class Builder implements DesignPattern { + + 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(); +// +// MediatorInsertion mi = new MediatorInsertion(main, builder, new ObjectNode("Hero")); +// design.addMediatorInsertion(mi); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Command.java b/src/main/java/designPatternExtensions/designPattern/Command.java new file mode 100644 index 0000000..c0a1fd4 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Command.java @@ -0,0 +1,23 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/command +//Stackで状態を元に戻したり、やり直したりする +//Mainで制御の移譲を行う必要あり? + + public class Command implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/"+this.getClass().getSimpleName()+".Json"); + ObjectNode wizard = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode goblin = design.getTransferContexts().getFirst().getDstFirstResource(); + + return design; + } + } \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Decorator.java b/src/main/java/designPatternExtensions/designPattern/Decorator.java new file mode 100644 index 0000000..1885ffb --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Decorator.java @@ -0,0 +1,34 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +//https://github.com/iluwatar/java-design-patterns/tree/master/decorator +//SimpleTrollを用いてClubbedTrollを作成しないとDecoratorとは言えない? +//仲介者オブジェクトM A->M->B M作成時にに、MにBを参照先を引数とするコンストラクタをつける +// public ClubbedTroll(SimpleTroll simpleTroll) { +// this.simpleTroll = simpleTroll; } + +public class Decorator implements DesignPattern { + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/Decorator.Json"); + ObjectNode simpleTroll = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode client = design.getTransferContexts().getFirst().getDstFirstResource(); + + ObjectNode clubbedTroll = new ObjectNode("ClubbedTroll"); + MediatorInsertion mi = new MediatorInsertion(client, simpleTroll, clubbedTroll); + design.addMediatorInsertion(mi); + + InterfaceNode troll = new InterfaceNode(clubbedTroll, "Troll"); + DependencyInversion di1 = new DependencyInversion(clubbedTroll, troll); + design.addDependencyInversion(di1); + + DependencyInversion di2 = new DependencyInversion(simpleTroll, troll); + design.addDependencyInversion(di2); + + return design; + } +} diff --git a/src/main/java/designPatternExtensions/designPattern/DesignPattern.java b/src/main/java/designPatternExtensions/designPattern/DesignPattern.java new file mode 100644 index 0000000..99bca0e --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/DesignPattern.java @@ -0,0 +1,8 @@ +package designPatternExtensions.designPattern; + +import models.objectOrientedTransfer.DataTransferDesign; +import models.objectOrientedTransfer.IllegalRelationException; + +public interface DesignPattern { + DataTransferDesign create() throws IllegalRelationException; +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Iterator.java b/src/main/java/designPatternExtensions/designPattern/Iterator.java new file mode 100644 index 0000000..79c9482 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Iterator.java @@ -0,0 +1,32 @@ +package designPatternExtensions.designPattern; +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +import java.util.ArrayList; +//メモ +//中身の構造を隠したまま、アイテムのタイプをifで回さなくても順番にデータを取り出す +// +//https://github.com/iluwatar/java-design-patterns/tree/master/iterator + + +public class Iterator implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/"+this.getClass().getSimpleName()+".Json"); + ObjectNode treasureChest = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode client = design.getTransferContexts().getFirst().getDstFirstResource(); + + ObjectNode iterator = new ObjectNode("TreasureChestItemIterator"); + MediatorInsertion mi = new MediatorInsertion(client, treasureChest, iterator); + design.addMediatorInsertion(mi); + + DependencyInversion di = new DependencyInversion( + iterator, new InterfaceNode(iterator, "Iterator")); + design.addDependencyInversion(di); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Memento.java b/src/main/java/designPatternExtensions/designPattern/Memento.java new file mode 100644 index 0000000..19b03f2 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Memento.java @@ -0,0 +1,36 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; + +import java.util.ArrayList; + +//https://github.com/iluwatar/java-design-patterns/tree/master/memento +//複数のデータ転送をまとめて扱えるようにしないとできない → 一方向でもできればいったんOK + +public class Memento implements DesignPattern{ + public DataTransferDesign create() throws IllegalRelationException { + ObjectNode star = new ObjectNode("Star"); + ObjectNode states = new ObjectNode("States"); + ObjectNode starMementoInternal = new ObjectNode("StarMementoInternal"); + + Relation transferRelation = new Relation(star, states, MultiplicityValue.OneToOne); + DataTransferContext context = new DataTransferContext( + new ArrayList<>(), transferRelation, starMementoInternal, "memento", PushPullValue.PULL + ); + + DataTransferDesign design = new DataTransferDesign(context); + + MediatorInsertion client = new MediatorInsertion(star, states, new ObjectNode("Client")); + design.addMediatorInsertion(client); + + DependencyInversion di = new DependencyInversion( + starMementoInternal, new InterfaceNode(starMementoInternal, "StarMemento"), states + ); + design.addDependencyInversion(di); + + return design; + } +} diff --git a/src/main/java/designPatternExtensions/designPattern/Observer.java b/src/main/java/designPatternExtensions/designPattern/Observer.java new file mode 100644 index 0000000..996d54e --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Observer.java @@ -0,0 +1,58 @@ +package designPatternExtensions.designPattern; +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import models.objectOrientedTransfer.*; +import java.util.ArrayList; +import java.util.List; + +//https://github.com/iluwatar/java-design-patterns/tree/master/observer +//依存性の逆転構造は再現できているが、OneToManyが使えないから再現できない? +// SubjectがObserverを記憶し(ManyToOne?PULL?)→DesignCraftが最初に登録してるものとする +// Clientから更新されたときに、Observerに通知する(OneToMany?PUSH?)→これが正解 +// + +public class Observer implements DesignPattern{ + public DataTransferDesign create() throws IllegalRelationException { + ObjectNode weather = new ObjectNode("Weather"); + ObjectNode orcs = new ObjectNode("Orcs"); + ObjectNode hobbits = new ObjectNode("Hobbits"); + ObjectNode data = new ObjectNode("WeatherType"); + + Relation transferRelation = new Relation(weather, orcs, MultiplicityValue.OneToOne); + DataTransferContext context = new DataTransferContext( + new ArrayList<>(), transferRelation, data, "currentWeather", PushPullValue.PUSH + ); + + DataTransferDesign design = new DataTransferDesign(context); + + DependencyInversion di1 = new DependencyInversion(orcs, new InterfaceNode(orcs, "WeatherObserver"), weather); + DependencyInversion di2 = new DependencyInversion(hobbits, new InterfaceNode(hobbits, "WeatherObserver"), weather); + design.addDependencyInversion(di1); + design.addDependencyInversion(di2); + + return design; + } +} + +//public class Observer { +// public static DataTransferDesign create() throws IllegalRelationException { +// ObjectNode weather = new ObjectNode("Weather"); +// ObjectNode orcs = new ObjectNode("Orcs"); +// ObjectNode hobbits = new ObjectNode("Hobbits"); +// ObjectNode data = new ObjectNode("WeatherType"); +// +// Relation transferRelation = new Relation(weather, orcs, MultiplicityValue.OneToOne); +// DataTransferContext context = new DataTransferContext( +// new ArrayList<>(), transferRelation, data, "currentWeather", PushPullValue.PUSH +// ); +// +// DataTransferDesign design = new DataTransferDesign(context); +// +// DependencyInversion di1 = new DependencyInversion(orcs, new InterfaceNode(orcs, "WeatherObserver"), weather); +// DependencyInversion di2 = new DependencyInversion(hobbits, new InterfaceNode(hobbits, "WeatherObserver"), weather); +// design.addDependencyInversion(di1); +// design.addDependencyInversion(di2); +// +// return design; +// } +//} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Prototype.java b/src/main/java/designPatternExtensions/designPattern/Prototype.java new file mode 100644 index 0000000..f6066ee --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Prototype.java @@ -0,0 +1,32 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import models.objectOrientedTransfer.*; + +import java.util.ArrayList; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/prototype + +public class Prototype implements DesignPattern{ + public DataTransferDesign create() throws IllegalRelationException { + ObjectNode heroFactoryImpl = new ObjectNode("HeroFactoryImpl"); + ObjectNode client = new ObjectNode("Client"); + ObjectNode beast = new ObjectNode("Beast"); + + Relation transferRelation = new Relation(heroFactoryImpl, client, MultiplicityValue.OneToOne); + DataTransferContext context = new DataTransferContext( + new ArrayList<>(), transferRelation, beast, "beast", PushPullValue.PULL + ); + + DataTransferDesign design = new DataTransferDesign(context); + + DependencyInversion di = new DependencyInversion( + heroFactoryImpl, new InterfaceNode(heroFactoryImpl, "HeroFactory"), client + ); + design.addDependencyInversion(di); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Proxy.java b/src/main/java/designPatternExtensions/designPattern/Proxy.java new file mode 100644 index 0000000..410f1ff --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Proxy.java @@ -0,0 +1,30 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +//https://github.com/iluwatar/java-design-patterns/tree/master/proxy + +public class Proxy implements DesignPattern{ + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/Proxy.Json"); + ObjectNode client = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode ivoryTower = design.getTransferContexts().getFirst().getDstFirstResource(); + + ObjectNode proxy = new ObjectNode("WizardTowerProxy"); + MediatorInsertion mi = new MediatorInsertion(client, ivoryTower, proxy); + design.addMediatorInsertion(mi); + + InterfaceNode wizardTower = new InterfaceNode(proxy, "WizardTower"); + DependencyInversion di = new DependencyInversion(proxy, wizardTower); + design.addDependencyInversion(di); + DependencyInversion di2 = new DependencyInversion(ivoryTower, wizardTower); + design.addDependencyInversion(di2); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Singleton.java b/src/main/java/designPatternExtensions/designPattern/Singleton.java new file mode 100644 index 0000000..1138454 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Singleton.java @@ -0,0 +1,23 @@ +package designPatternExtensions.designPattern; + +import models.objectOrientedTransfer.*; + +import java.util.ArrayList; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/singleton + +public class Singleton implements DesignPattern{ + public DataTransferDesign create() throws IllegalRelationException { + ObjectNode client = new ObjectNode("Client"); + ObjectNode enumIvoryTower = new ObjectNode("EnumIvoryTower"); + ObjectNode data = new ObjectNode("data"); + + Relation transferRelation = new Relation(enumIvoryTower, client, MultiplicityValue.OneToOne); + DataTransferContext context = new DataTransferContext( + new ArrayList<>(), transferRelation, data, "data", PushPullValue.PULL + ); + + return new DataTransferDesign(context); + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/State.java b/src/main/java/designPatternExtensions/designPattern/State.java new file mode 100644 index 0000000..ca462f9 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/State.java @@ -0,0 +1,27 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.*; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +//https://github.com/iluwatar/java-design-patterns/tree/master/state +// Mammoth内でConcreteStateのMapを持てたら再現できたといえる? + +public class State implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/State.Json"); + ObjectNode main = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode concreteState = design.getTransferContexts().getFirst().getDstFirstResource(); + +// MediatorInsertion mi = new MediatorInsertion( +// main, concreteState, new ObjectNode("Mammoth")); +// design.addMediatorInsertion(mi); + + DependencyInversion di = new DependencyInversion( + concreteState, new InterfaceNode(concreteState, "State")); + design.addDependencyInversion(di); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Strategy.java b/src/main/java/designPatternExtensions/designPattern/Strategy.java new file mode 100644 index 0000000..56ffed2 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Strategy.java @@ -0,0 +1,54 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import models.objectOrientedTransfer.*; +import designPatternExtensions.ModelLoader; + +import java.util.ArrayList; +import java.util.List; + +//https://github.com/iluwatar/java-design-patterns/tree/master/strategy +//同じ役割の実装クラスを複数用意できない-> ConcreteStrategy + +public class Strategy implements DesignPattern{ + + public DataTransferDesign create() throws IllegalRelationException { + DataTransferDesign design = ModelLoader.load("models/designPattern/Strategy.Json"); + ObjectNode dragonSlayer = design.getTransferContexts().getFirst().getSrcFirstResource(); + ObjectNode concreteStrategy = (ObjectNode) design.getTransferContexts().getFirst().getDstResource().get(0).getDestination(); + + DependencyInversion di = new DependencyInversion( + concreteStrategy, new InterfaceNode(concreteStrategy, "DragonSlayingStrategy")); + design.addDependencyInversion(di); + + return design; + } +} + +//public class Strategy implements DesignPattern{ +// +// public DataTransferDesign create() throws IllegalRelationException { +// List srcEdges = new ArrayList<>(); +// List dstEdges = new ArrayList<>(); +// ObjectNode main = new ObjectNode("Main"); +// ObjectNode dragonSlayer = new ObjectNode("DragonSlayer"); +// ObjectNode meleeStrategy = new ObjectNode("MeleeStrategy"); +// ObjectNode data = new ObjectNode("BattleExecute"); +// srcEdges.add(new ReferenceEdge(main, dragonSlayer, "dragonSlayer")); +// dstEdges.add(new ReferenceEdge(main, meleeStrategy, "meleeStrategy", "Integer")); +// List relations = new ArrayList<>(); +// relations.add(new Relation(main, dstEdges, MultiplicityValue.OneToOne)); +// Relation transferRelation = new Relation(srcEdges, dstEdges, MultiplicityValue.OneToOne); +// DataTransferContext context = new DataTransferContext(relations, transferRelation, data, "battleExecute", PushPullValue.PUSH); +// DataTransferDesign design = new DataTransferDesign(context); +// +// DependencyInversion di = new DependencyInversion( +// meleeStrategy, new InterfaceNode(meleeStrategy, "DragonSlayingStrategy"), dragonSlayer +// ); +// design.addDependencyInversion(di); +// +// return design; +// } +// +//} diff --git a/src/main/java/designPatternExtensions/designPattern/TemplateMethod.java b/src/main/java/designPatternExtensions/designPattern/TemplateMethod.java new file mode 100644 index 0000000..c3cc290 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/TemplateMethod.java @@ -0,0 +1,43 @@ +package designPatternExtensions.designPattern; + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import models.objectOrientedTransfer.*; + +import java.util.ArrayList; +import java.util.List; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/template-method + +public class TemplateMethod implements DesignPattern { + + public DataTransferDesign create() throws IllegalRelationException { + List srcEdges = new ArrayList<>(); + List dstEdges = new ArrayList<>(); + ObjectNode main = new ObjectNode("Main"); + ObjectNode halflingThief = new ObjectNode("HalflingThief"); + ObjectNode subtleMethod = new ObjectNode("SubtleMethod"); + ObjectNode data = new ObjectNode("data"); + + srcEdges.add(new ReferenceEdge(main, halflingThief, "halflingThief")); + dstEdges.add(new ReferenceEdge(main, subtleMethod, "method", "Integer")); + + List relations = new ArrayList<>(); + relations.add(new Relation(main, dstEdges, MultiplicityValue.OneToOne)); + Relation transferRelation = new Relation(srcEdges, dstEdges, MultiplicityValue.OneToOne); + + DataTransferContext context = new DataTransferContext( + relations, transferRelation, data, "data", PushPullValue.PUSH + ); + + DataTransferDesign design = new DataTransferDesign(context); + + DependencyInversion di = new DependencyInversion( + subtleMethod, new InterfaceNode(subtleMethod, "StealingMethod"), halflingThief + ); + design.addDependencyInversion(di); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/designPatternExtensions/designPattern/Visitor.java b/src/main/java/designPatternExtensions/designPattern/Visitor.java new file mode 100644 index 0000000..4007d72 --- /dev/null +++ b/src/main/java/designPatternExtensions/designPattern/Visitor.java @@ -0,0 +1,48 @@ +package designPatternExtensions.designPattern; + +//メモ +//https://github.com/iluwatar/java-design-patterns/tree/master/visitor +//Commander->Sergent(Children) 1:多の転送ができないため不可能 +//制御の委譲をできるようにする必要がある(自分の作業) + +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import models.objectOrientedTransfer.*; + +import java.util.ArrayList; +import java.util.List; + +public class Visitor implements DesignPattern{ + + public DataTransferDesign create() throws IllegalRelationException { + List srcEdges = new ArrayList<>(); + List dstEdges = new ArrayList<>(); + ObjectNode commander = new ObjectNode("Commander"); + ObjectNode sergent = new ObjectNode("Sergent"); + ObjectNode soldier = new ObjectNode("Soldier"); + ObjectNode client = new ObjectNode("Client"); + ObjectNode main = new ObjectNode("Main"); + ObjectNode visitor = new ObjectNode("SoldierVisitor"); + + ReferenceEdge srcEdge = new ReferenceEdge(commander, sergent, "children", "Integer"); + srcEdges.add(srcEdge); + srcEdge = new ReferenceEdge(sergent, soldier, "children", "Integer"); + srcEdges.add(srcEdge); + ReferenceEdge dstEdge = new ReferenceEdge(main, client, "client"); + dstEdges.add(dstEdge); + + Relation transferRelation = new Relation(srcEdges, dstEdges, MultiplicityValue.OneToOne); + DataTransferContext context = new DataTransferContext( + new ArrayList<>(), transferRelation, visitor, "visitor", PushPullValue.PULL + ); + + DataTransferDesign design = new DataTransferDesign(context); + + DependencyInversion di = new DependencyInversion( + visitor, new InterfaceNode(visitor, "UnitVisitor"), commander + ); + design.addDependencyInversion(di); + + return design; + } +} \ No newline at end of file diff --git a/src/main/java/generators/ASTGenerator.java b/src/main/java/generators/ASTGenerator.java index 8ed2456..b6024fd 100644 --- a/src/main/java/generators/ASTGenerator.java +++ b/src/main/java/generators/ASTGenerator.java @@ -4,6 +4,9 @@ import java.util.List; import ast.*; +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.InterfaceNode; +import designPatternExtensions.MediatorInsertion; import models.algebra.Type; import models.dataConstraintModel.MapType; import models.objectOrientedTransfer.*; @@ -16,7 +19,7 @@ public static final String mapPostfix = "Map"; public static final String mapGet = "get"; public static final String mapPut = "put"; - + public static String toComponentName(String name) { return name.substring(0, 1).toUpperCase() + name.substring(1); } @@ -24,13 +27,20 @@ public static String toVariableName(String name) { return name.substring(0, 1).toLowerCase() + name.substring(1); } - + public static Codebase generate(DataTransferDesign dataTransferDesign) { Codebase codebase = new Codebase(); DeltaComplex deltaComplex = dataTransferDesign.getDeltaComplex(); for (Delta delta: deltaComplex.split()) { codebase = weaveDelta(codebase, delta); } + // do not change flow : MediatorInsertion -> DependencyInversion + for (MediatorInsertion mi: dataTransferDesign.getMediatorInsertions()) { + codebase = weaveMediatorInsertion(codebase, mi); + } + for (DependencyInversion di: dataTransferDesign.getDependencyInversions()) { + codebase = weaveDependencyInversion(codebase, di); + } return codebase; } @@ -43,7 +53,7 @@ return codebase; } } - + public static Codebase weavePrimitiveDelta(Codebase codebase, PrimitiveDelta primitiveDelta) { if (primitiveDelta instanceof PrimitivePullDelta) { codebase = weavePrimitivePullDelta(codebase, (PrimitivePullDelta) primitiveDelta); @@ -81,7 +91,7 @@ field23 = createField(class2, pullEdge2.getName() + mapPostfix, typeKeyToType3); // class2 -> {class3} (PULL) } FieldDeclaration field13 = createField(class1, pullEdge2.getName(), type3); // class1 -> class3 (create) - + // Construct getter method MethodDeclaration getter = createMethod(class2, getterPrefix + toComponentName(pullEdge2.getName())); ReturnStatement return23 = new ReturnStatement(); @@ -98,7 +108,7 @@ } getter.addStatement(return23); getter.setReturnType(type3); - + // Construct coordinator method MethodDeclaration coordionator = createMethod(class1, updateMethodPrefix + toComponentName(pullEdge2.getName())); FieldAccess field3 = new FieldAccess(new ThisExpression(), field13.getName()); // this.name3 @@ -142,7 +152,7 @@ field13 = createField(class1, pushEdge.getName() + mapPostfix, typeKeyToType3); // class1 -> {class3} (PUSH) } FieldDeclaration field32 = createField(class3, pullEdge.getName(), type2); // class3 -> class2 (create) - + // Construct setter method MethodDeclaration setter = null; if (!pushEdge.toMany()) { @@ -156,7 +166,7 @@ Assignment assignment = new Assignment(field2, new Variable(toVariableName(name2))); // this.name2 = name2; ExpressionStatement assignmentStatement = new ExpressionStatement(assignment); setter.addStatement(assignmentStatement); - + // Construct coordinator method MethodDeclaration coordionator = createMethod(class1, updateMethodPrefix + toComponentName(name2)); List args = new ArrayList<>(); @@ -195,7 +205,7 @@ FieldDeclaration field12 = createField(class1, pushEdge1.getName(), type2); // class1 -> class2 (PUSH) FieldDeclaration field23 = createField(class2, pushEdge2.getName(), type3); // class2 -> class3 (PUSH) FieldDeclaration field31 = createField(class3, toVariableName(name1), type1); // class3 -> class1 (create) - + // Construct setter in class3 MethodDeclaration setter3 = createMethod(class3, setterPrefix + toComponentName(name1)); VariableDeclaration param1 = new VariableDeclaration(type1, name1); @@ -224,7 +234,233 @@ coordionator.addStatement(new ExpressionStatement(callSetter)); return codebase; } - + + public static Codebase weaveMediatorInsertion(Codebase codebase, MediatorInsertion mediatorInsertion) { + ObjectNode srcNode = mediatorInsertion.getSrc(); + ObjectNode dstNode = mediatorInsertion.getDst(); + ObjectNode mediatorNode = mediatorInsertion.getMediator(); + String srcName = toComponentName(srcNode.getName()); + String dstName = toComponentName(dstNode.getName()); + String mediatorName = toComponentName(mediatorNode.getName()); + String mediatorFieldName = toVariableName(mediatorName); + String dstFieldName = toVariableName(dstName); + + models.algebra.Type dstType = codebase.getComponentType(dstName); + + // Create a Mediator class and add a field of type dst + TypeDeclaration mediatorClass = createClass(codebase, mediatorName); + models.algebra.Type mediatorType = codebase.getComponentType(mediatorName); + FieldDeclaration dstField = createField(mediatorClass, dstFieldName, dstType); + + // Add delegation methods to the Mediator that forward calls to dst's public methods + TypeDeclaration dstClass = createClass(codebase, dstName); + for (MethodDeclaration method: dstClass.getMethods()) { + if (method.isConstructor()) continue; + MethodDeclaration delegateMethod = createMethod(mediatorClass, method.getName()); + delegateMethod.setReturnType(method.getReturnType()); + List args = new ArrayList<>(); + if (method.getParameters() != null) { + for (VariableDeclaration param: method.getParameters()) { + delegateMethod.addParameter(param); + args.add(new Variable(param.getName())); + } + } + FieldAccess dstAccess = new FieldAccess(dstField.getName()); + MethodInvocation callDst = new MethodInvocation(dstAccess, method.getName(), args); + if (method.getReturnType() != null) { + ReturnStatement returnStatement = new ReturnStatement(); + returnStatement.setExpression(callDst); + delegateMethod.addStatement(returnStatement); + } else { + delegateMethod.addStatement(new ExpressionStatement(callDst)); + } + } + + // Replace the dst-type field in src with a Mediator-type field + TypeDeclaration srcClass = createClass(codebase, srcName); + for (FieldDeclaration field: srcClass.getFields()) { + if (field.getType() != null && field.getType().getTypeName().equals(dstType.getTypeName())) { + field.setType(mediatorType); + field.setName(mediatorFieldName); + } else if (field.getType() instanceof MapType) { + MapType mapType = (MapType) field.getType(); + if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName())) { + field.setType(codebase.getMapType(mapType.getKeyType().getTypeName(), mediatorName)); + field.setName(mediatorFieldName); + } + } + } + + // 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) { + for (VariableDeclaration param: method.getParameters()) { + if (param.getType() != null && param.getType().getTypeName().equals(dstType.getTypeName())) { + param.setType(mediatorType); + param.setName(mediatorFieldName); + } + } + } + } + + // Replace all references to the dst field with references to the mediator field in the bodies of src's methods + for (MethodDeclaration method: srcClass.getMethods()) { + if (method.getBody() == null) continue; + for (Statement statement: method.getBody().getStatements2()) { + replaceFieldNameInStatement(statement, dstFieldName, mediatorFieldName); + } + } + + // Replace return type and MapType value type matching dst type with Mediator type in all classes + for (CompilationUnit cu: codebase.getCompilationUnits()) { + TypeDeclaration cls = cu.types().getFirst(); + for (MethodDeclaration method: cls.getMethods()) { + if (!method.isConstructor() && method.getReturnType() != null) { + if (method.getReturnType().getTypeName().equals(dstType.getTypeName())) { + method.setReturnType(mediatorType); + } + } + } + for (FieldDeclaration field: cls.getFields()) { + if (field.getType() instanceof MapType) { + MapType mapType = (MapType) field.getType(); + if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName())) { + field.setType(codebase.getMapType(mapType.getKeyType().getTypeName(), mediatorName)); + } + } + } + } + return codebase; + } + + private static void replaceFieldNameInStatement(Statement statement, String oldName, String newName) { + if (statement instanceof ExpressionStatement) { + replaceFieldNameInExpression(((ExpressionStatement) statement).getExpression(), oldName, newName); + } + } + + private static void replaceFieldNameInExpression(Expression expr, String oldName, String newName) { + if (expr instanceof MethodInvocation) { + MethodInvocation mi = (MethodInvocation) expr; + if (mi.getReceiver() instanceof FieldAccess) { + FieldAccess fa = (FieldAccess) mi.getReceiver(); + if (fa.getFieldName().equals(oldName)) { + fa.setFieldName(newName); + } + } + for (Expression arg: mi.getArguments()) { + replaceFieldNameInExpression(arg, oldName, newName); + } + } else if (expr instanceof Assignment) { + Assignment assignment = (Assignment) expr; + if (assignment.getLeft() instanceof FieldAccess) { + FieldAccess fa = (FieldAccess) assignment.getLeft(); + if (fa.getFieldName().equals(oldName)) { + fa.setFieldName(newName); + } + } + if (assignment.getRight() instanceof Variable) { + Variable var = (Variable) assignment.getRight(); + if (var.getName().equals(oldName)) { + assignment.setRight(new Variable(newName)); + } + } + replaceFieldNameInExpression(assignment.getLeft(), oldName, newName); + replaceFieldNameInExpression(assignment.getRight(), oldName, newName); + } + } + + public static Codebase weaveDependencyInversion(Codebase codebase, DependencyInversion dependencyInversion) { + ObjectNode dstNode = dependencyInversion.getDst(); + InterfaceNode interfaceNode = dependencyInversion.getInterfaceNode(); + String dstName = toComponentName(dstNode.getName()); + String interfaceName = toComponentName(interfaceNode.getName()); + + //print -> public interface interfaceName { ... } + InterfaceDeclaration interfaceDeclaration = createInterface(codebase, interfaceName); + + TypeDeclaration dstClass = createClass(codebase, dstName); + for (MethodDeclaration method: dstClass.getMethods()) { + if (!method.isConstructor()) { + boolean alreadyExists = interfaceDeclaration.getMethods().stream() + .anyMatch(m -> m.getName().equals(method.getName())); + if (!alreadyExists) { + interfaceDeclaration.addMethod(method); + } + } + } + + // public class "dstClass" implements "interfaceName" + if (!dstClass.getImplementsInterfaces().contains(interfaceName)) { + dstClass.addImplementsInterface(interfaceName); + } + + models.algebra.Type interfaceType = codebase.getComponentType(interfaceName); + models.algebra.Type dstType = codebase.getComponentType(dstName); + + // // Change dst class method return types + replaceDepedencyInClass(codebase, dstClass, dstType, interfaceType, interfaceName); + + if (dependencyInversion.getTargetSrc() != null) { + // Traverse only the specified target class + String targetSrcName = toComponentName(dependencyInversion.getTargetSrc().getName()); + TypeDeclaration srcClass = createClass(codebase, targetSrcName); + replaceDepedencyInClass(codebase, srcClass, dstType, interfaceType, interfaceName); + } else { + // Traverse all dependent classes(srcClass) in Codebase + for (CompilationUnit cu: codebase.getCompilationUnits()) { + TypeDeclaration srcClass = cu.types().getFirst(); + if (srcClass.getTypeName().equals(dstName)) continue; + replaceDepedencyInClass(codebase, srcClass, dstType, interfaceType, interfaceName); + } + } + return codebase; + } + + private static void replaceDepedencyInClass(Codebase codebase, TypeDeclaration srcClass, models.algebra.Type dstType, models.algebra.Type interfaceType, String interfaceName) { + for (FieldDeclaration field: srcClass.getFields()) { + if (field.getType().equals(dstType)) { + // private Companies companies → private ICompanies companies + field.setType(interfaceType); + } else if (field.getType() instanceof MapType) { + MapType mapType = (MapType) field.getType(); + // Map → Map + if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName())) { + field.setType(codebase.getMapType(mapType.getKeyType().getTypeName(), interfaceName)); + } + } + } + + for (MethodDeclaration method: srcClass.getMethods()) { + // Change constructor parameter types + if (method.isConstructor() && method.getParameters() != null) { + for (VariableDeclaration param: method.getParameters()) { + if (param.getType() != null && param.getType().equals(dstType)) { + // Customer(Companies companies) → Customer(ICompanies companies) + param.setType(interfaceType); + } + } + } + // Change method return types + if (!method.isConstructor() && method.getReturnType() != null) { + if (method.getReturnType().getTypeName().equals(dstType.getTypeName())) { + // public Company getCompany() → public ICompany getCompany() + method.setReturnType(interfaceType); + } + } + } + } + + private static InterfaceDeclaration createInterface(Codebase codebase, String name) { + if (codebase.getInterfaceCompilationUnit(name) != null) { + return codebase.getInterfaceCompilationUnit(name).interfaces().getFirst(); + } + InterfaceDeclaration interfaceDeclaration = new InterfaceDeclaration(name); + CompilationUnit compilationUnit = new CompilationUnit(interfaceDeclaration); + codebase.addInterfaceCompilationUnit(name, compilationUnit); + return interfaceDeclaration; + } + private static TypeDeclaration createClass(Codebase codebase, String name) { if (codebase.getCompilationUnit(name) != null) return codebase.getCompilationUnit(name).types().getFirst(); TypeDeclaration type = new TypeDeclaration(name); @@ -232,7 +468,7 @@ codebase.addCompilationUnit(name, compilationUnit); return type; } - + private static MethodDeclaration createMethod(TypeDeclaration type, String name) { for (MethodDeclaration method: type.getMethods()) { if (method.getName().equals(name)) return method; @@ -241,7 +477,7 @@ type.addMethod(method); return method; } - + private static MethodDeclaration createConstructor(TypeDeclaration type) { for (MethodDeclaration method: type.getMethods()) { if (method.getName().equals(type.getTypeName())) return method; @@ -250,7 +486,7 @@ type.addMethod(method); return method; } - + private static FieldDeclaration createField(TypeDeclaration type, String fieldName, models.algebra.Type fieldType) { for (FieldDeclaration field: type.getFields()) { if (field.getName().equals(fieldName)) return field; @@ -259,4 +495,4 @@ type.addField(field); return field; } -} +} \ No newline at end of file diff --git a/src/main/java/generators/Codebase.java b/src/main/java/generators/Codebase.java index 2b5ae0f..a7f229f 100644 --- a/src/main/java/generators/Codebase.java +++ b/src/main/java/generators/Codebase.java @@ -11,6 +11,7 @@ public class Codebase { private Map classes = new HashMap<>(); + private Map interfaces = new HashMap<>(); private Map componentTypes = new HashMap<>(); private Map standardTypes = new HashMap<>(); @@ -52,12 +53,25 @@ models.algebra.Type newType = new models.algebra.Type(name, new SimpleType(name)); componentTypes.put(name, newType); } - + + public CompilationUnit getInterfaceCompilationUnit(String name) { + return interfaces.get(name); + } + + public void addInterfaceCompilationUnit(String name, CompilationUnit compilationUnit) { + interfaces.put(name, compilationUnit); + models.algebra.Type newType = new models.algebra.Type(name, new SimpleType(name)); + componentTypes.put(name, newType); + } + public String toString() { String code = ""; for (CompilationUnit cu: classes.values()) { code += cu.toString(); } + for (CompilationUnit cu: interfaces.values()) { + code += cu.toString(); + } return code; } } diff --git a/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java b/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java index 6baa035..e05cac9 100644 --- a/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java +++ b/src/main/java/models/objectOrientedTransfer/DataTransferDesign.java @@ -1,5 +1,8 @@ package models.objectOrientedTransfer; +import designPatternExtensions.DependencyInversion; +import designPatternExtensions.MediatorInsertion; + import parser.*; import parser.exceptions.ExpectedJsonValue; @@ -16,6 +19,8 @@ public class DataTransferDesign { private List transferContexts; private DeltaComplex deltaComplex; + private List dependencyInversions = new ArrayList<>(); + private List mediatorInsertions = new ArrayList<>(); public DataTransferDesign(DataTransferContext transferContext) throws IllegalRelationException { this.transferContexts = new ArrayList<>(); @@ -23,15 +28,31 @@ this.deltaComplex = createDefaultDeltaComlex(transferContext); } - public DataTransferDesign(JsonValue jsonValue) throws IllegalRelationException { - this.transferContexts = new ArrayList<>(); - for (StringValue keyValue : jsonValue.getJson().keySet()) { - String key = keyValue.getStringValue(); - if (key.equals("contexts")) { - ArrayValue arrayValue = (ArrayValue) jsonValue.getValue(keyValue); - setTransferContexts(arrayValue); - } - } + public DataTransferDesign(JsonValue jsonValue) throws IllegalRelationException { + this.transferContexts = new ArrayList<>(); + for (StringValue keyValue : jsonValue.getJson().keySet()) { + String key = keyValue.getStringValue(); + if (key.equals("contexts")) { + ArrayValue arrayValue = (ArrayValue) jsonValue.getValue(keyValue); + setTransferContexts(arrayValue); + } + } + } + + public void addDependencyInversion(DependencyInversion dependencyInversion) { + dependencyInversions.add(dependencyInversion); + } + + public List getDependencyInversions() { + return dependencyInversions; + } + + public void addMediatorInsertion(MediatorInsertion mediatorInsertion) { + mediatorInsertions.add(mediatorInsertion); + } + + public List getMediatorInsertions() { + return mediatorInsertions; } public DeltaComplex createDefaultDeltaComlex(DataTransferContext transferContext) throws IllegalRelationException { @@ -40,11 +61,11 @@ if (transferContext.getTransferMultiplicity() == MultiplicityValue.ManyToOne || transferContext.getTransferMultiplicity() == MultiplicityValue.OneToOne) { // Simple PUSH - + // Construct all deltas. Stack deltaStack = new Stack<>(); ReferenceEdge bottomReference = constructDefaultDeltas(transferContext, deltaStack); - + // Add the data transfer delta. ObjectNode srcObj = (ObjectNode) bottomReference.getSource(); ObjectNode dstObj = (ObjectNode) transferContext.getDataType(); @@ -53,7 +74,7 @@ PrimitivePullPushDelta primDelta = new PrimitivePullPushDelta(dataEdge, bottomReference, dataName); // PUSH data transfer Delta dataTransferDelta = new Delta(primDelta); DeltaComplex deltaComplex = new DeltaComplex(dataTransferDelta); - + // Add initialization deltas. while (!deltaStack.isEmpty()) { deltaComplex.attach(deltaStack.pop()); @@ -70,7 +91,7 @@ // Construct all deltas. Stack deltaStack = new Stack<>(); ReferenceEdge bottomReference = constructDefaultDeltas(transferContext, deltaStack); - + // Add the data transfer delta. ObjectNode srcObj = (ObjectNode) bottomReference.getDestination(); ObjectNode dstObj = (ObjectNode) transferContext.getDataType(); @@ -79,7 +100,7 @@ PrimitivePullDelta primDelta = new PrimitivePullDelta(bottomReference, dataEdge, dataName); // PULL data transfer Delta dataTransferDelta = new Delta(primDelta); DeltaComplex deltaComplex = new DeltaComplex(dataTransferDelta); - + // Add initialization deltas. while (!deltaStack.isEmpty()) { deltaComplex.attach(deltaStack.pop()); @@ -142,7 +163,7 @@ } } } - + // 1) Create container passing deltas. List primitiveDeltaList = new ArrayList<>(); for (ReferenceEdge dstEdge: oneDestination) { @@ -178,13 +199,13 @@ prevReference = new ReferenceEdge(srcObj, dstObj, dataName); } } - - if (!toOne && + + if (!toOne && ((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, // then the reference to select one destination object from potential multiple objects is needed. - + // 2) Create a component identifying delta. PrimitiveDelta componentSelectingDelta = null; for (ReferenceEdge dstEdge: manyDestinations) { @@ -215,7 +236,7 @@ prevReference = new ReferenceEdge(srcObj, dstObj, dataName); } } - + // 3) Create a component obtaining delta. if (primitiveDeltaList.size() > 0) { Delta delta = null; diff --git a/src/main/java/models/objectOrientedTransfer/Relation.java b/src/main/java/models/objectOrientedTransfer/Relation.java index 0cd68aa..c0100f1 100644 --- a/src/main/java/models/objectOrientedTransfer/Relation.java +++ b/src/main/java/models/objectOrientedTransfer/Relation.java @@ -42,7 +42,7 @@ this.dstResourceNode = dstResourceNode; this.multiplicity = multiplicity; } - + public boolean isFlat() { return isFlat; } diff --git a/src/test/java/parser/PatternTest.java b/src/test/java/parser/PatternTest.java new file mode 100644 index 0000000..31e54ab --- /dev/null +++ b/src/test/java/parser/PatternTest.java @@ -0,0 +1,35 @@ +package parser; + +import designPatternExtensions.designPattern.*; +import generators.ASTGenerator; +import org.junit.jupiter.api.Test; + +public class PatternTest { + + @Test void abstractFactory() throws Exception { run(new AbstractFactory()); } + @Test void adapter() throws Exception { run(new Adapter()); } + @Test void bridge() throws Exception { run(new Bridge()); } + @Test void builder() throws Exception { run(new Builder()); } +// @Test void chainOfResponsibility() throws Exception { run(new ChainOfResponsibility()); } + @Test void command() throws Exception { run(new Command()); } + @Test void decorator() throws Exception { run(new Decorator()); } +// @Test void facade() throws Exception { run(new Facade()); } +// @Test void factoryMethod() throws Exception { run(new FactoryMethod()); } +// @Test void interpreter() throws Exception { run(new Interpreter()); } + @Test void iterator() throws Exception { run(new Iterator()); } +// @Test void mediator() throws Exception { run(new Mediator()); } + @Test void memento() throws Exception { run(new Memento()); } + @Test void observer() throws Exception { run(new Observer()); } + @Test void prototype() throws Exception { run(new Prototype()); } + @Test void proxy() throws Exception { run(new Proxy()); } + @Test void singleton() throws Exception { run(new Singleton()); } + @Test void state() throws Exception { run(new State()); } + @Test void strategy() throws Exception { run(new Strategy()); } + @Test void templateMethod() throws Exception { run(new TemplateMethod()); } + @Test void visitor() throws Exception { run(new Visitor()); } + + private void run(DesignPattern pattern) throws Exception { + System.out.println(pattern.getClass().getSimpleName()); + System.out.println(ASTGenerator.generate(pattern.create())); + } +} \ No newline at end of file diff --git a/src/test/java/parser/TestParser.java b/src/test/java/parser/TestParser.java index 08faf1b..3c51bc3 100644 --- a/src/test/java/parser/TestParser.java +++ b/src/test/java/parser/TestParser.java @@ -18,7 +18,9 @@ @Test void testCustomerManagement(){ - File file = new File("models/CustomerManagement.Json"); + //File file = new File("models/CustomerManagement.Json"); + File file = new File("models/designPattern/Adapter.Json"); + try { Parser parser = new Parser(new BufferedReader(new FileReader(file))); Value jsonValue = parser.getValue();