diff --git a/README.md b/README.md index 5469a10..93779e6 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,44 @@ Enter the path to the Jar file in the field provided. 🎉 You can now use the Modeling Language to its full extent directly in VSCode! ### Stand-alone use + +The CLI can also be used independently of the VSCode plugin. In this case, input and output are usually via files, +the path of which is also specified in the command. + +In general, the CLI can be called by executing the JAR file. + +```shell +java -jar ./target/model-modeling-language-cli-1.0-SNAPSHOT.jar +``` + +In the following we use the alias `mmlcli`. + +```text +Usage: mmlcli [-hV] [COMMAND] + -h, --help Show this help message and exit. + -V, --version Print version information and exit. +``` + +#### Generate +The `generate` command is used to generate Ecore and XMI files from the serialized MML format. By default, the input +is via STDIN, the output is in the form of the generated files in a specified directory. Optionally, a file whose +content is in serialized MML format can be specified instead of the STDIN input. + +```text +Usage: mmlcli generate [-f[=SERIALIZED]] + Name of the entire project/workspace + Path to the output directory + -f, --file[=SERIALIZED] Path to the serialized workspace as json file +``` + +#### Serialize +The serialize command is used to serialize Ecore files into the MML format. The entry is made by specifying a path +to an Ecore file. The output is via STDOUT by default, but optionally a path to an output file can also be specified +in which the serialized model is to be saved. + +```text +Usage: mmlcli serialize [-o[=SERIALIZED]] + Path to an Ecore file + -o, --out[=SERIALIZED] Path to the output directory +``` + diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index 4834865..e80c2ab 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -45,7 +45,6 @@ META-INF/*.SF META-INF/*.DSA META-INF/*.RSA - META-INF/** about.html about.ini about.mappings @@ -55,6 +54,30 @@ plugin.xml + + com.google.code.gson:gson + + META-INF/** + + + + org.eclipse.emf:* + + META-INF/** + + + + info.picocli:picocli + + META-INF/** + + + + commons-io:commons-io + + META-INF/** + + @@ -62,6 +85,28 @@ + + + org.junit.jupiter + junit-jupiter + 5.10.1 + test + + + junit-jupiter-api + org.junit.jupiter + + + junit-jupiter-params + org.junit.jupiter + + + junit-jupiter-engine + org.junit.jupiter + + + + 17 17 diff --git a/pom.xml b/pom.xml index c771b03..de174d6 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,6 @@ META-INF/*.SF META-INF/*.DSA META-INF/*.RSA - META-INF/** about.html about.ini about.mappings @@ -68,6 +67,30 @@ plugin.xml + + com.google.code.gson:gson + + META-INF/** + + + + org.eclipse.emf:* + + META-INF/** + + + + info.picocli:picocli + + META-INF/** + + + + commons-io:commons-io + + META-INF/** + + @@ -82,6 +105,17 @@ picocli 4.7.5 + + commons-io + commons-io + 2.15.1 + + + org.junit.jupiter + junit-jupiter + 5.10.1 + test + org.eclipse.emf org.eclipse.emf.ecore @@ -96,11 +130,27 @@ org.eclipse.emf org.eclipse.emf.ecore.xmi 2.36.0 + + + org.eclipse.emf + org.eclipse.emf.ecore + + org.eclipse.emf org.eclipse.emf.edit 2.20.0 + + + org.eclipse.emf + org.eclipse.emf.common + + + org.eclipse.emf + org.eclipse.emf.ecore + + com.google.code.gson diff --git a/src/main/java/de/nexus/mmlcli/ModelModelingLanguageCLI.java b/src/main/java/de/nexus/mmlcli/ModelModelingLanguageCLI.java index 7ef6379..c70a9c6 100644 --- a/src/main/java/de/nexus/mmlcli/ModelModelingLanguageCLI.java +++ b/src/main/java/de/nexus/mmlcli/ModelModelingLanguageCLI.java @@ -1,9 +1,10 @@ package de.nexus.mmlcli; import de.nexus.mmlcli.generator.GeneratorCommand; +import de.nexus.mmlcli.serializer.SerializeCommand; import picocli.CommandLine; -@CommandLine.Command(name = "mmlcli", mixinStandardHelpOptions = true, version = "v1.0.0", description = "CLI for interaction between MML, EMF and HiPE", subcommands = {GeneratorCommand.class}) +@CommandLine.Command(name = "mmlcli", mixinStandardHelpOptions = true, version = "v1.0.0", description = "CLI for interaction between MML, EMF and HiPE", subcommands = {GeneratorCommand.class, SerializeCommand.class}) public class ModelModelingLanguageCLI { public static void main(String... args) { int exitCode = new CommandLine(new ModelModelingLanguageCLI()).execute(args); diff --git a/src/main/java/de/nexus/mmlcli/entities/instance/AttributeEntry.java b/src/main/java/de/nexus/mmlcli/entities/instance/AttributeEntry.java new file mode 100644 index 0000000..56134ae --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/instance/AttributeEntry.java @@ -0,0 +1,27 @@ +package de.nexus.mmlcli.entities.instance; + +/** + * Dataclass for an instance attribute + */ +public class AttributeEntry { + private String name; + private String typeId; + private T value; + private boolean isEnumType; + + public String getTypeId() { + return typeId; + } + + public String getName() { + return name; + } + + public T getValue() { + return value; + } + + public boolean isEnumType() { + return isEnumType; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/instance/GeneratorInstance.java b/src/main/java/de/nexus/mmlcli/entities/instance/GeneratorInstance.java new file mode 100644 index 0000000..8e306ec --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/instance/GeneratorInstance.java @@ -0,0 +1,19 @@ +package de.nexus.mmlcli.entities.instance; + +import java.util.ArrayList; + +/** + * Dataclass for a generator of a single XMI file + */ +public class GeneratorInstance { + private String instanceName; + private ArrayList instances; + + public String getInstanceName() { + return instanceName; + } + + public ArrayList getInstances() { + return instances; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/instance/GeneratorInstanceWrapper.java b/src/main/java/de/nexus/mmlcli/entities/instance/GeneratorInstanceWrapper.java new file mode 100644 index 0000000..4050779 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/instance/GeneratorInstanceWrapper.java @@ -0,0 +1,14 @@ +package de.nexus.mmlcli.entities.instance; + +import java.util.ArrayList; + +/** + * Dataclass for list of generators for multiple XMI files + */ +public class GeneratorInstanceWrapper { + private final ArrayList serializedInstances = new ArrayList<>(); + + public ArrayList getSerializedInstances() { + return serializedInstances; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/instance/ObjectInstance.java b/src/main/java/de/nexus/mmlcli/entities/instance/ObjectInstance.java new file mode 100644 index 0000000..2fee279 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/instance/ObjectInstance.java @@ -0,0 +1,34 @@ +package de.nexus.mmlcli.entities.instance; + +import java.util.ArrayList; + +/** + * Dataclass for an instance + */ +public class ObjectInstance { + private String referenceId; + private String referenceTypeId; + private String name; + private ArrayList> attributes; + private ArrayList references; + + public String getReferenceId() { + return referenceId; + } + + public String getReferenceTypeId() { + return referenceTypeId; + } + + public String getName() { + return name; + } + + public ArrayList> getAttributes() { + return attributes; + } + + public ArrayList getReferences() { + return references; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/instance/ReferenceEntry.java b/src/main/java/de/nexus/mmlcli/entities/instance/ReferenceEntry.java new file mode 100644 index 0000000..3c7d195 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/instance/ReferenceEntry.java @@ -0,0 +1,24 @@ +package de.nexus.mmlcli.entities.instance; + +import java.util.ArrayList; + +/** + * Dataclass for an instance reference + */ +public class ReferenceEntry { + private String name; + private String typeId; + private ArrayList referencedIds; + + public String getName() { + return name; + } + + public String getTypeId() { + return typeId; + } + + public ArrayList getReferencedIds() { + return referencedIds; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/AbstractClassEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/AbstractClassEntity.java new file mode 100644 index 0000000..402cee3 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/AbstractClassEntity.java @@ -0,0 +1,105 @@ +package de.nexus.mmlcli.entities.model; + +import de.nexus.mmlcli.serializer.EcoreIdResolver; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; + +import java.util.ArrayList; +import java.util.UUID; +import java.util.stream.Collectors; + +/*** + * Dataclass for a class-like (Abstract class, class or interface) + */ +public class AbstractClassEntity { + private String referenceId; + private String name; + private boolean isAbstract; + private boolean isInterface; + private final ArrayList> attributes = new ArrayList<>(); + private final ArrayList references = new ArrayList<>(); + private final ArrayList extendsIds = new ArrayList<>(); + private final ArrayList implementsIds = new ArrayList<>(); + + public String getReferenceId() { + return referenceId; + } + + public String getName() { + return name; + } + + public boolean isAbstract() { + return isAbstract; + } + + public boolean isInterface() { + return isInterface; + } + + public ArrayList> getAttributes() { + return attributes; + } + + public ArrayList getReferences() { + return references; + } + + public ArrayList getExtendsIds() { + return extendsIds; + } + + public ArrayList getImplementsIds() { + return implementsIds; + } + + private void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + + private void setName(String name) { + this.name = name; + } + + private void setAbstract(boolean anAbstract) { + isAbstract = anAbstract; + } + + private void setInterface(boolean anInterface) { + isInterface = anInterface; + } + + + @Override + public String toString() { + String attributeString = attributes.isEmpty() ? "" + : "\n" + attributes.stream().map(AttributeEntity::toString).collect(Collectors.joining(",")) + "\n"; + String referenceString = references.isEmpty() ? "" + : "\n" + references.stream().map(CReferenceEntity::toString).collect(Collectors.joining(",")) + "\n"; + return String.format("%s(isAbstract:%b|isInterface:%b||%s||%s)", name, isAbstract, isInterface, attributeString, + referenceString); + } + + + public static AbstractClassEntity fromEClass(EClass clazz, EcoreIdResolver idResolver) { + AbstractClassEntity classEntity = new AbstractClassEntity(); + UUID uuid = idResolver.resolveId(clazz); + classEntity.setReferenceId(uuid.toString()); + classEntity.setName(clazz.getName()); + classEntity.setAbstract(clazz.isAbstract()); + classEntity.setInterface(clazz.isInterface()); + + clazz.getEStructuralFeatures().forEach(sFeat -> { + if (sFeat instanceof EAttribute attr) { + classEntity.attributes.add(AttributeEntity.fromEAttribute(attr, idResolver)); + } else if (sFeat instanceof EReference ref) { + classEntity.references.add(CReferenceEntity.fromEReference(ref, idResolver)); + } + }); + + classEntity.extendsIds.addAll(clazz.getESuperTypes().stream().map(sClazz -> idResolver.resolveId(sClazz).toString()).toList()); + + return classEntity; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/AttributeEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/AttributeEntity.java new file mode 100644 index 0000000..3357ecb --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/AttributeEntity.java @@ -0,0 +1,120 @@ +package de.nexus.mmlcli.entities.model; + +import de.nexus.mmlcli.generator.EmfGraphBuilderUtils; +import de.nexus.mmlcli.serializer.EcoreIdResolver; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EEnumLiteral; + +import java.util.UUID; + +/** + * Dataclass for a class attribute + */ +public class AttributeEntity { + private String referenceId; + private String name; + private String type; + private boolean isEnumType; + private boolean hasDefaultValue; + private T defaultValue; + private ClassElementModifiers modifiers; + + public String getReferenceId() { + return referenceId; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public boolean isEnumType() { + return isEnumType; + } + + public boolean isHasDefaultValue() { + return hasDefaultValue; + } + + public T getDefaultValue() { + return defaultValue; + } + + public ClassElementModifiers getModifiers() { + return modifiers; + } + + private void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + + private void setName(String name) { + this.name = name; + } + + private void setType(String type) { + this.type = type; + } + + private void setEnumType(boolean enumType) { + isEnumType = enumType; + } + + private void setHasDefaultValue(boolean hasDefaultValue) { + this.hasDefaultValue = hasDefaultValue; + } + + private void setDefaultValue(T defaultValue) { + this.defaultValue = defaultValue; + } + + private void setModifiers(ClassElementModifiers modifiers) { + this.modifiers = modifiers; + } + + @Override + public String toString() { + return String.format("%s<%s>", name, type); + } + + public static AttributeEntity fromEAttribute(EAttribute eAttribute, EcoreIdResolver idResolver) { + AttributeEntity attribute = new AttributeEntity<>(); + UUID uuid = idResolver.resolveId(eAttribute); + attribute.setReferenceId(uuid.toString()); + attribute.setName(eAttribute.getName()); + if (eAttribute.getEType() instanceof EEnum) { + attribute.setEnumType(true); + attribute.setType(idResolver.resolveId(eAttribute.getEType()).toString()); + + if (eAttribute.getDefaultValue() != null && !EmfGraphBuilderUtils.isETypeDefaultValue((EDataType) eAttribute.getEType(), eAttribute.getDefaultValue())) { + attribute.setHasDefaultValue(true); + attribute.setDefaultValue(EmfGraphBuilderUtils.mapVals("-", idResolver.resolveId((EEnumLiteral) eAttribute.getDefaultValue()))); + } else { + attribute.setHasDefaultValue(false); + } + } else if (eAttribute.getEType() instanceof EDataType) { + attribute.setEnumType(false); + attribute.setType(EmfGraphBuilderUtils.mapETypes((EDataType) eAttribute.getEType())); + + if (eAttribute.getDefaultValue() != null && !EmfGraphBuilderUtils.isETypeDefaultValue((EDataType) eAttribute.getEType(), eAttribute.getDefaultValue())) { + attribute.setHasDefaultValue(true); + attribute.setDefaultValue(EmfGraphBuilderUtils.mapVals(eAttribute.getEAttributeType(), eAttribute.getDefaultValue())); + } else { + attribute.setHasDefaultValue(false); + } + } else { + throw new IllegalArgumentException("Unexpected attribute type: " + eAttribute.getEType().toString()); + } + + ClassElementModifiers modifiers = new ClassElementModifiers(!eAttribute.isChangeable(), eAttribute.isVolatile(), eAttribute.isTransient(), eAttribute.isUnsettable(), eAttribute.isDerived(), eAttribute.isUnique(), eAttribute.isOrdered(), false, false, eAttribute.isID()); + attribute.setModifiers(modifiers); + + + return attribute; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/CReferenceEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/CReferenceEntity.java new file mode 100644 index 0000000..414af40 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/CReferenceEntity.java @@ -0,0 +1,128 @@ +package de.nexus.mmlcli.entities.model; + +import de.nexus.mmlcli.serializer.EcoreIdResolver; +import org.eclipse.emf.ecore.EReference; + +import java.util.UUID; + +/** + * Dataclass for class references + */ +public class CReferenceEntity { + private String referenceId; + private String name; + private MultiplicityEntity multiplicity; + private String type; + private ClassElementModifiers modifiers; + private boolean hasOpposite; + private String opposite; + + public String getReferenceId() { + return referenceId; + } + + public String getName() { + return name; + } + + public MultiplicityEntity getMultiplicity() { + return multiplicity; + } + + public String getType() { + return type; + } + + public ClassElementModifiers getModifiers() { + return modifiers; + } + + public boolean isHasOpposite() { + return hasOpposite; + } + + public String getOpposite() { + return opposite; + } + + private void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + + private void setName(String name) { + this.name = name; + } + + private void setMultiplicity(MultiplicityEntity multiplicity) { + this.multiplicity = multiplicity; + } + + private void setType(String type) { + this.type = type; + } + + private void setModifiers(ClassElementModifiers modifiers) { + this.modifiers = modifiers; + } + + private void setHasOpposite(boolean hasOpposite) { + this.hasOpposite = hasOpposite; + } + + private void setOpposite(String opposite) { + this.opposite = opposite; + } + + @Override + public String toString() { + return String.format("(%s -> %s)", name, type); + } + + public static CReferenceEntity fromEReference(EReference eRef, EcoreIdResolver idResolver) { + CReferenceEntity refEntity = new CReferenceEntity(); + UUID uuid = idResolver.resolveId(eRef); + refEntity.setReferenceId(uuid.toString()); + refEntity.setName(eRef.getName()); + refEntity.setType(idResolver.resolveId(eRef.getEType()).toString()); + MultiplicityEntity mult; + if (eRef.getLowerBound() != 0) { + if (eRef.getUpperBound() != 1) { + if (eRef.getLowerBound() == 1 && eRef.getUpperBound() == -1) { + mult = new MultiplicityEntity(false, true, false, false, false, 0, 0); + } else { + if (eRef.getUpperBound() == -1) { + mult = new MultiplicityEntity(true, false, false, false, true, eRef.getLowerBound(), 0); + } else { + mult = new MultiplicityEntity(false, false, false, false, false, eRef.getLowerBound(), eRef.getUpperBound()); + } + } + } else { + mult = new MultiplicityEntity(false, false, false, false, false, eRef.getLowerBound(), 0); + } + } else { + if (eRef.getUpperBound() != 1) { + if (eRef.getUpperBound() == -1) { + mult = new MultiplicityEntity(false, false, true, false, false, 0, 0); + } else { + mult = new MultiplicityEntity(true, false, false, false, false, 0, eRef.getUpperBound()); + } + } else { + mult = new MultiplicityEntity(true, false, false, false, false, 0, 1); + } + } + refEntity.setMultiplicity(mult); + + + if (eRef.getEOpposite() != null) { + refEntity.setHasOpposite(true); + refEntity.setOpposite(idResolver.resolveId(eRef.getEOpposite()).toString()); + } else { + refEntity.setHasOpposite(false); + } + + ClassElementModifiers modifiers = new ClassElementModifiers(!eRef.isChangeable(), eRef.isVolatile(), eRef.isTransient(), eRef.isUnsettable(), eRef.isDerived(), eRef.isUnique(), eRef.isOrdered(), eRef.isResolveProxies(), eRef.isContainment(), false); + refEntity.setModifiers(modifiers); + + return refEntity; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/ClassElementModifiers.java b/src/main/java/de/nexus/mmlcli/entities/model/ClassElementModifiers.java new file mode 100644 index 0000000..b222029 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/ClassElementModifiers.java @@ -0,0 +1,74 @@ +package de.nexus.mmlcli.entities.model; + +import com.google.gson.annotations.SerializedName; + +/** + * Dataclass for class modifiers + */ +public class ClassElementModifiers { + private boolean readonly; + @SerializedName("volatile") + private boolean _volatile; + @SerializedName("transient") + private boolean _transient; + private boolean unsettable; + private boolean derived; + private boolean unique; + private boolean ordered; + private boolean resolve; + private boolean containment; + private boolean id; + + public boolean isReadonly() { + return readonly; + } + + public boolean isVolatile() { + return _volatile; + } + + public boolean isTransient() { + return _transient; + } + + public boolean isUnsettable() { + return unsettable; + } + + public boolean isDerived() { + return derived; + } + + public boolean isUnique() { + return unique; + } + + public boolean isOrdered() { + return ordered; + } + + public boolean isResolve() { + return resolve; + } + + public boolean isContainment() { + return containment; + } + + public boolean isId() { + return id; + } + + public ClassElementModifiers(boolean readonly, boolean _volatile, boolean _transient, boolean unsettable, boolean derived, boolean unique, boolean ordered, boolean resolve, boolean containment, boolean id) { + this.readonly = readonly; + this._volatile = _volatile; + this._transient = _transient; + this.unsettable = unsettable; + this.derived = derived; + this.unique = unique; + this.ordered = ordered; + this.resolve = resolve; + this.containment = containment; + this.id = id; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/EnumEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/EnumEntity.java new file mode 100644 index 0000000..857f42f --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/EnumEntity.java @@ -0,0 +1,62 @@ +package de.nexus.mmlcli.entities.model; + +import de.nexus.mmlcli.serializer.EcoreIdResolver; +import org.eclipse.emf.ecore.EEnum; + +import java.util.ArrayList; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Dataclass for a enum + */ +public class EnumEntity { + private String referenceId; + private String name; + private String type; + private final ArrayList> entries = new ArrayList<>(); + + public String getReferenceId() { + return referenceId; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public ArrayList> getEntries() { + return entries; + } + + private void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + + private void setName(String name) { + this.name = name; + } + + private void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return String.format("ENUM<%s,%s>{%s}", name, type, entries.isEmpty() ? "" + : entries.stream().map(EnumEntryEntity::toString).collect(Collectors.joining(","))); + } + + public static EnumEntity fromEEnum(EEnum eenum, EcoreIdResolver idResolver) { + EnumEntity enumEntity = new EnumEntity<>(); + UUID uuid = idResolver.resolveId(eenum); + enumEntity.setName(eenum.getName()); + enumEntity.setReferenceId(uuid.toString()); + enumEntity.setType("int"); // we assume type int since EMF does not allow other enum types + enumEntity.entries.addAll(eenum.getELiterals().stream().map(lit -> EnumEntryEntity.fromEEnumLiteral(lit, idResolver)).toList()); + return enumEntity; + } +} \ No newline at end of file diff --git a/src/main/java/de/nexus/mmlcli/entities/model/EnumEntryEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/EnumEntryEntity.java new file mode 100644 index 0000000..b49f5c7 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/EnumEntryEntity.java @@ -0,0 +1,63 @@ +package de.nexus.mmlcli.entities.model; + +import de.nexus.mmlcli.serializer.EcoreIdResolver; +import org.eclipse.emf.ecore.EEnumLiteral; + +import java.util.UUID; + +/** + * Dataclass for a single enum entry + */ +public class EnumEntryEntity { + private String referenceId; + private String name; + private boolean hasDefaultValue; + private T defaultValue; + + public String getReferenceId() { + return referenceId; + } + + public String getName() { + return name; + } + + public boolean isHasDefaultValue() { + return hasDefaultValue; + } + + public T getDefaultValue() { + return defaultValue; + } + + private void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + + private void setName(String name) { + this.name = name; + } + + private void setHasDefaultValue(boolean hasDefaultValue) { + this.hasDefaultValue = hasDefaultValue; + } + + private void setDefaultValue(T defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public String toString() { + return String.format("[%s|%b]", name, hasDefaultValue); + } + + public static EnumEntryEntity fromEEnumLiteral(EEnumLiteral eLit, EcoreIdResolver idResolver) { + EnumEntryEntity enumEntry = new EnumEntryEntity<>(); + UUID uuid = idResolver.resolveId(eLit); + enumEntry.setName(eLit.getName()); + enumEntry.setReferenceId(uuid.toString()); + enumEntry.setDefaultValue(eLit.getValue()); + enumEntry.setHasDefaultValue(true); + return enumEntry; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/ModelEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/ModelEntity.java new file mode 100644 index 0000000..ec7c9e7 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/ModelEntity.java @@ -0,0 +1,27 @@ +package de.nexus.mmlcli.entities.model; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +/** + * Dataclass for a complete metamodel + */ +public class ModelEntity { + private final ArrayList packages = new ArrayList<>(); + + public ArrayList getPackages() { + return packages; + } + + @Override + public String toString() { + return packages.isEmpty() ? "" + : "\n" + packages.stream().map(PackageEntity::toString).collect(Collectors.joining(",")) + "\n"; + } + + public static ModelEntity fromPackageEntity(PackageEntity pckgEntity) { + ModelEntity model = new ModelEntity(); + model.packages.add(pckgEntity); + return model; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/MultiplicityEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/MultiplicityEntity.java new file mode 100644 index 0000000..d199419 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/MultiplicityEntity.java @@ -0,0 +1,52 @@ +package de.nexus.mmlcli.entities.model; + +/** + * Dataclass for reference multiplicities + */ +public class MultiplicityEntity { + private boolean hasUpperBound; + private boolean lowerIsN; + private boolean lowerIsN0; + private boolean upperIsN; + private boolean upperIsN0; + private int lower; + private int upper; + + public boolean isHasUpperBound() { + return hasUpperBound; + } + + public boolean isLowerIsN() { + return lowerIsN; + } + + public boolean isLowerIsN0() { + return lowerIsN0; + } + + public boolean isUpperIsN() { + return upperIsN; + } + + public boolean isUpperIsN0() { + return upperIsN0; + } + + public int getLower() { + return lower; + } + + public int getUpper() { + return upper; + } + + public MultiplicityEntity(boolean hasUpperBound, boolean lowerIsN, boolean lowerIsN0, boolean upperIsN, boolean upperIsN0, int lower, int upper) { + this.hasUpperBound = hasUpperBound; + this.lowerIsN = lowerIsN; + this.lowerIsN0 = lowerIsN0; + this.upperIsN = upperIsN; + this.upperIsN0 = upperIsN0; + this.lower = lower; + this.upper = upper; + } +} diff --git a/src/main/java/de/nexus/mmlcli/entities/model/PackageEntity.java b/src/main/java/de/nexus/mmlcli/entities/model/PackageEntity.java new file mode 100644 index 0000000..d54a58d --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/entities/model/PackageEntity.java @@ -0,0 +1,72 @@ +package de.nexus.mmlcli.entities.model; + +import de.nexus.mmlcli.serializer.EcoreIdResolver; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EPackage; + +import java.util.ArrayList; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Dataclass for a package + */ +public class PackageEntity { + private String referenceId; + private String name; + private final ArrayList abstractClasses = new ArrayList<>(); + private final ArrayList> enums = new ArrayList<>(); + private final ArrayList subPackages = new ArrayList<>(); + + public String getReferenceId() { + return referenceId; + } + + public String getName() { + return name; + } + + public ArrayList getAbstractClasses() { + return abstractClasses; + } + + public ArrayList> getEnums() { + return enums; + } + + public ArrayList getSubPackages() { + return subPackages; + } + + private void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + + private void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + String classesString = abstractClasses.isEmpty() ? "" + : "\n" + abstractClasses.stream().map(AbstractClassEntity::toString).collect(Collectors.joining(",")) + + "\n"; + String enumsString = enums.isEmpty() ? "" + : "\n" + enums.stream().map(EnumEntity::toString).collect(Collectors.joining(",")) + "\n"; + String subPackagesString = subPackages.isEmpty() ? "" + : "\n" + subPackages.stream().map(PackageEntity::toString).collect(Collectors.joining(",")) + "\n"; + return String.format("%s{%s %s %s}", name, classesString, enumsString, subPackagesString); + } + + public static PackageEntity fromEPackage(EPackage ePackage, EcoreIdResolver idResolver) { + PackageEntity packageEntity = new PackageEntity(); + UUID uuid = idResolver.resolveId(ePackage); + packageEntity.setName(ePackage.getName()); + packageEntity.setReferenceId(uuid.toString()); + packageEntity.subPackages.addAll(ePackage.getESubpackages().stream().map(subPackage -> fromEPackage(subPackage, idResolver)).toList()); + packageEntity.enums.addAll(ePackage.getEClassifiers().stream().filter(classifier -> classifier instanceof EEnum).map(eenum -> EnumEntity.fromEEnum((EEnum) eenum, idResolver)).toList()); + packageEntity.abstractClasses.addAll(ePackage.getEClassifiers().stream().filter(classifier -> classifier instanceof EClass).map(eclass -> AbstractClassEntity.fromEClass((EClass) eclass, idResolver)).toList()); + return packageEntity; + } +} diff --git a/src/main/java/de/nexus/mmlcli/generator/DeserializedDocument.java b/src/main/java/de/nexus/mmlcli/generator/DeserializedDocument.java index afd5739..a9f1620 100644 --- a/src/main/java/de/nexus/mmlcli/generator/DeserializedDocument.java +++ b/src/main/java/de/nexus/mmlcli/generator/DeserializedDocument.java @@ -2,8 +2,8 @@ package de.nexus.mmlcli.generator; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import de.nexus.mmlcli.generator.entities.instance.GeneratorInstanceWrapper; -import de.nexus.mmlcli.generator.entities.model.ModelEntity; +import de.nexus.mmlcli.entities.instance.GeneratorInstanceWrapper; +import de.nexus.mmlcli.entities.model.ModelEntity; public class DeserializedDocument { private ModelEntity typegraph; @@ -17,9 +17,24 @@ public class DeserializedDocument { return this.instancegraph; } + private void setTypegraph(ModelEntity typegraph) { + this.typegraph = typegraph; + } + + private void setInstancegraph(GeneratorInstanceWrapper instancegraph) { + this.instancegraph = instancegraph; + } + public static DeserializedDocument build(String json) { GsonBuilder builder = new GsonBuilder(); Gson gson = builder.create(); return gson.fromJson(json, DeserializedDocument.class); } + + public static DeserializedDocument build(ModelEntity model) { + DeserializedDocument doc = new DeserializedDocument(); + doc.setTypegraph(model); + doc.setInstancegraph(new GeneratorInstanceWrapper()); + return doc; + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/EcoreTypeGraphBuilder.java b/src/main/java/de/nexus/mmlcli/generator/EcoreTypeGraphBuilder.java index c503415..ca25d80 100644 --- a/src/main/java/de/nexus/mmlcli/generator/EcoreTypeGraphBuilder.java +++ b/src/main/java/de/nexus/mmlcli/generator/EcoreTypeGraphBuilder.java @@ -1,256 +1,242 @@ package de.nexus.mmlcli.generator; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - +import de.nexus.mmlcli.entities.model.*; import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EEnum; -import org.eclipse.emf.ecore.EEnumLiteral; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EcoreFactory; -import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.*; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl; -import de.nexus.mmlcli.generator.entities.model.AbstractClassEntity; -import de.nexus.mmlcli.generator.entities.model.AttributeEntity; -import de.nexus.mmlcli.generator.entities.model.CReferenceEntity; -import de.nexus.mmlcli.generator.entities.model.EnumEntity; -import de.nexus.mmlcli.generator.entities.model.EnumEntryEntity; -import de.nexus.mmlcli.generator.entities.model.PackageEntity; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Stream; /** * The EcoreTypeGraphBuilder contains all functions to generate a metamodel from a PackageEntity as an Ecore file. */ public class EcoreTypeGraphBuilder { - private final EPackage ePackage; - private final String exportPath; - private final EcoreTypeResolver resolver; + private final EPackage ePackage; + private final String exportPath; + private final EcoreTypeResolver resolver; - /** - * Build an Ecore Package - * @param pckg PackageEntity - * @param targetUri Package URI - * @param exportPath Path for the Ecore export - * @param resolver EcoreTypeResolver - */ - public EcoreTypeGraphBuilder(PackageEntity pckg, String targetUri, String exportPath, EcoreTypeResolver resolver) { - // create a new package - this.ePackage = createPackage(pckg.getName(), pckg.getName(), targetUri); - this.exportPath = exportPath; - this.resolver = resolver; + /** + * Build an Ecore Package + * + * @param pckg PackageEntity + * @param targetUri Package URI + * @param exportPath Path for the Ecore export + * @param resolver EcoreTypeResolver + */ + public EcoreTypeGraphBuilder(PackageEntity pckg, String targetUri, String exportPath, EcoreTypeResolver resolver) { + // create a new package + this.ePackage = createPackage(pckg.getName(), pckg.getName(), targetUri); + this.exportPath = exportPath; + this.resolver = resolver; - // store package in the resolver - resolver.store(pckg.getReferenceId(), this.ePackage); + // store package in the resolver + resolver.store(pckg.getReferenceId(), this.ePackage); - // build subpackages - pckg.getSubPackages().forEach(subPckg -> { - EPackage subPackage = new EcoreTypeGraphBuilder(subPckg, targetUri, resolver).getAsSubpackage(); - this.ePackage.getESubpackages().add(subPackage); - }); - - // build classes - pckg.getAbstractClasses().forEach(ab -> { - EClass clss = createEClass(ab); - ab.getAttributes().forEach(attr -> addAttribute(clss, attr)); - ab.getReferences().forEach(cref -> addReference(clss, cref)); - }); - - // build enums - pckg.getEnums().forEach(enm -> { - EEnum enmm = createEEnum(enm); - enm.getEntries().forEach(ee -> addEEnumLiteral(enmm, ee, enm)); - }); - } + // build subpackages + pckg.getSubPackages().forEach(subPckg -> { + EPackage subPackage = new EcoreTypeGraphBuilder(subPckg, targetUri, resolver).getAsSubpackage(); + this.ePackage.getESubpackages().add(subPackage); + }); - /** - * /** - * Build an Ecore Package - *

- * Does not include an export path, since this is used for subpackages - * - * @param pckg PackageEntity - * @param targetUri Package URI - * @param resolver EcoreTypeResolver - */ - public EcoreTypeGraphBuilder(PackageEntity pckg, String targetUri, EcoreTypeResolver resolver) { - this(pckg, targetUri, null, resolver); - } + // build classes + pckg.getAbstractClasses().forEach(ab -> { + EClass clss = createEClass(ab); + ab.getAttributes().forEach(attr -> addAttribute(clss, attr)); + ab.getReferences().forEach(cref -> addReference(clss, cref)); + }); - /** - * Export EPackages to Ecore files - * - * @param graphBuilderList List of EcoreTypeGraphBuilders - * @param resolver EcoreTypeResolver - * @param resSet Common resource set - */ - public static void buildEcoreFile(List graphBuilderList, EcoreTypeResolver resolver, - ResourceSet resSet) { - // resolve all unresolved types - resolver.resolveUnresovedTypes(); + // build enums + pckg.getEnums().forEach(enm -> { + EEnum enmm = createEEnum(enm); + enm.getEntries().forEach(ee -> addEEnumLiteral(enmm, ee, enm)); + }); + } - for (EcoreTypeGraphBuilder builder : graphBuilderList) { - builder.ePackage.eClass(); - } - Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; - Map m = reg.getExtensionToFactoryMap(); - m.put(EcorePackage.eNAME, new EcoreResourceFactoryImpl()); + /** + * /** + * Build an Ecore Package + *

+ * Does not include an export path, since this is used for subpackages + * + * @param pckg PackageEntity + * @param targetUri Package URI + * @param resolver EcoreTypeResolver + */ + public EcoreTypeGraphBuilder(PackageEntity pckg, String targetUri, EcoreTypeResolver resolver) { + this(pckg, targetUri, null, resolver); + } - List resources = new ArrayList<>(); - // create a resource - try { - for (EcoreTypeGraphBuilder builder : graphBuilderList) { - Resource resource = resSet - .createResource(URI.createFileURI(Objects.requireNonNull(builder.exportPath))); - /* - * add your EPackage as root, everything is hierarchical included in this first - * node - */ - resource.getContents().add(builder.ePackage); - resources.add(resource); - } - } catch (NullPointerException e) { - e.printStackTrace(); - } + /** + * Export EPackages to Ecore files + * + * @param graphBuilderList List of EcoreTypeGraphBuilders + * @param resolver EcoreTypeResolver + * @param resSet Common resource set + */ + public static void buildEcoreFile(List graphBuilderList, EcoreTypeResolver resolver, + ResourceSet resSet) { + // resolve all unresolved types + resolver.resolveUnresovedTypes(); - // now save the content. - for (Resource resource : resources) { - try { - resource.save(Collections.EMPTY_MAP); - } catch (IOException e) { - e.printStackTrace(); - } - } - } + for (EcoreTypeGraphBuilder builder : graphBuilderList) { + builder.ePackage.eClass(); + } + Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; + Map m = reg.getExtensionToFactoryMap(); + m.put(EcorePackage.eNAME, new EcoreResourceFactoryImpl()); - public EPackage getAsSubpackage() { - return this.ePackage; - } + List resources = new ArrayList<>(); + // create a resource + try { + for (EcoreTypeGraphBuilder builder : graphBuilderList) { + Resource resource = resSet + .createResource(URI.createFileURI(Objects.requireNonNull(builder.exportPath))); + /* + * add your EPackage as root, everything is hierarchical included in this first + * node + */ + resource.getContents().add(builder.ePackage); + resources.add(resource); + } + } catch (NullPointerException e) { + e.printStackTrace(); + } - @SuppressWarnings("unchecked") - private void addAttribute(EClass containerClass, AttributeEntity attr) { - final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute(); - resolver.store(attr.getReferenceId(), attribute); - // always add to container first - containerClass.getEStructuralFeatures().add(attribute); - attribute.setName(attr.getName()); - attribute.setLowerBound(0); - attribute.setUpperBound(1); + // now save the content. + for (Resource resource : resources) { + try { + resource.save(Collections.EMPTY_MAP); + } catch (IOException e) { + e.printStackTrace(); + } + } + } - if (attr.isEnumType()) { - resolver.resolveAttributeEnum(attribute, (AttributeEntity) attr); - } else { - attribute.setEType(EmfGraphBuilderUtils.mapETypes(attr.getType())); + public EPackage getAsSubpackage() { + return this.ePackage; + } - if (attr.isHasDefaultValue()) { - Object val = EmfGraphBuilderUtils.mapVals(attr.getType(), attr.getDefaultValue()); - attribute.setDefaultValue(val); - } - } - - attribute.setDerived(attr.getModifiers().isDerived()); - attribute.setOrdered(attr.getModifiers().isOrdered()); - attribute.setTransient(attr.getModifiers().isTransient()); - attribute.setUnique(attr.getModifiers().isUnique()); - attribute.setUnsettable(attr.getModifiers().isUnsettable()); - attribute.setVolatile(attr.getModifiers().isVolatile()); - attribute.setChangeable(!attr.getModifiers().isReadonly()); - attribute.setID(attr.getModifiers().isId()); - } + @SuppressWarnings("unchecked") + private void addAttribute(EClass containerClass, AttributeEntity attr) { + final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute(); + resolver.store(attr.getReferenceId(), attribute); + // always add to container first + containerClass.getEStructuralFeatures().add(attribute); + attribute.setName(attr.getName()); + attribute.setLowerBound(0); + attribute.setUpperBound(1); - private void addReference(EClass containerClass, CReferenceEntity cref) { - final EReference reference = EcoreFactory.eINSTANCE.createEReference(); - resolver.store(cref.getReferenceId(), reference); - // always add to container first - containerClass.getEStructuralFeatures().add(reference); - reference.setName(cref.getName()); + if (attr.isEnumType()) { + resolver.resolveAttributeEnum(attribute, (AttributeEntity) attr); + } else { + attribute.setEType(EmfGraphBuilderUtils.mapETypes(attr.getType())); - resolver.resolveReference(reference, cref); + if (attr.isHasDefaultValue()) { + Object val = EmfGraphBuilderUtils.mapVals(attr.getType(), attr.getDefaultValue()); + attribute.setDefaultValue(val); + } + } - if (cref.getMultiplicity().isLowerIsN0()) { - reference.setLowerBound(0); - } else if (cref.getMultiplicity().isLowerIsN()) { - reference.setLowerBound(1); - } else { - reference.setLowerBound(cref.getMultiplicity().getLower()); - } + attribute.setDerived(attr.getModifiers().isDerived()); + attribute.setOrdered(attr.getModifiers().isOrdered()); + attribute.setTransient(attr.getModifiers().isTransient()); + attribute.setUnique(attr.getModifiers().isUnique()); + attribute.setUnsettable(attr.getModifiers().isUnsettable()); + attribute.setVolatile(attr.getModifiers().isVolatile()); + attribute.setChangeable(!attr.getModifiers().isReadonly()); + attribute.setID(attr.getModifiers().isId()); + } - if (cref.getMultiplicity().isHasUpperBound()) { - if (cref.getMultiplicity().isUpperIsN0() || cref.getMultiplicity().isUpperIsN()) { - reference.setUpperBound(-1); - } else { - reference.setUpperBound(cref.getMultiplicity().getUpper()); - } - } else { - if (cref.getMultiplicity().isLowerIsN0() || cref.getMultiplicity().isLowerIsN()) { - reference.setUpperBound(-1); - } else { - reference.setUpperBound(1); - } - } + private void addReference(EClass containerClass, CReferenceEntity cref) { + final EReference reference = EcoreFactory.eINSTANCE.createEReference(); + resolver.store(cref.getReferenceId(), reference); + // always add to container first + containerClass.getEStructuralFeatures().add(reference); + reference.setName(cref.getName()); - reference.setDerived(cref.getModifiers().isDerived()); - reference.setChangeable(!cref.getModifiers().isReadonly()); - reference.setVolatile(cref.getModifiers().isVolatile()); - reference.setUnsettable(cref.getModifiers().isUnsettable()); - reference.setUnique(cref.getModifiers().isUnique()); - reference.setTransient(cref.getModifiers().isTransient()); - reference.setOrdered(cref.getModifiers().isOrdered()); - reference.setResolveProxies(cref.getModifiers().isResolve()); - } + resolver.resolveReference(reference, cref); - private EPackage createPackage(final String name, final String prefix, final String uri) { - final EPackage epackage = EcoreFactory.eINSTANCE.createEPackage(); - epackage.setName(name); - epackage.setNsPrefix(prefix); - epackage.setNsURI(uri); - return epackage; + if (cref.getMultiplicity().isLowerIsN0()) { + reference.setLowerBound(0); + } else if (cref.getMultiplicity().isLowerIsN()) { + reference.setLowerBound(1); + } else { + reference.setLowerBound(cref.getMultiplicity().getLower()); + } - } + if (cref.getMultiplicity().isHasUpperBound()) { + if (cref.getMultiplicity().isUpperIsN0() || cref.getMultiplicity().isUpperIsN()) { + reference.setUpperBound(-1); + } else { + reference.setUpperBound(cref.getMultiplicity().getUpper()); + } + } else { + if (cref.getMultiplicity().isLowerIsN0() || cref.getMultiplicity().isLowerIsN()) { + reference.setUpperBound(-1); + } else { + reference.setUpperBound(1); + } + } - private EClass createEClass(final AbstractClassEntity ace) { - final EClass eClass = EcoreFactory.eINSTANCE.createEClass(); - resolver.store(ace.getReferenceId(), eClass); - eClass.setName(ace.getName()); - eClass.setAbstract(ace.isAbstract()); - eClass.setInterface(ace.isInterface()); - if (!ace.getExtendsIds().isEmpty() || !ace.getImplementsIds().isEmpty()) { - List allSupertypes = Stream.concat(ace.getExtendsIds().stream(), ace.getImplementsIds().stream()) - .toList(); - resolver.resolveSupertypes(eClass, allSupertypes); - } - this.ePackage.getEClassifiers().add(eClass); - return eClass; - } + reference.setDerived(cref.getModifiers().isDerived()); + reference.setChangeable(!cref.getModifiers().isReadonly()); + reference.setVolatile(cref.getModifiers().isVolatile()); + reference.setUnsettable(cref.getModifiers().isUnsettable()); + reference.setUnique(cref.getModifiers().isUnique()); + reference.setTransient(cref.getModifiers().isTransient()); + reference.setOrdered(cref.getModifiers().isOrdered()); + reference.setResolveProxies(cref.getModifiers().isResolve()); + reference.setContainment(cref.getModifiers().isContainment()); + } - private EEnum createEEnum(final EnumEntity ee) { - final EEnum eenum = EcoreFactory.eINSTANCE.createEEnum(); - resolver.store(ee.getReferenceId(), eenum); - eenum.setName(ee.getName()); - this.ePackage.getEClassifiers().add(eenum); - return eenum; - } + private EPackage createPackage(final String name, final String prefix, final String uri) { + final EPackage epackage = EcoreFactory.eINSTANCE.createEPackage(); + epackage.setName(name); + epackage.setNsPrefix(prefix); + epackage.setNsURI(uri); + return epackage; - private EEnumLiteral addEEnumLiteral(final EEnum ee, final EnumEntryEntity eee, final EnumEntity eentity) { - final EEnumLiteral eenumLit = EcoreFactory.eINSTANCE.createEEnumLiteral(); - resolver.store(eee.getReferenceId(), eenumLit); - eenumLit.setName(eee.getName()); - if (eee.isHasDefaultValue()) { - if (eentity.getType().equals("int") || eentity.getType().equals("float") - || eentity.getType().equals("double")) { - int val = Double.valueOf(eee.getDefaultValue().toString()).intValue(); - eenumLit.setValue(val); - } - } - ee.getELiterals().add(eenumLit); - return eenumLit; - } + } + + private EClass createEClass(final AbstractClassEntity ace) { + final EClass eClass = EcoreFactory.eINSTANCE.createEClass(); + resolver.store(ace.getReferenceId(), eClass); + eClass.setName(ace.getName()); + eClass.setAbstract(ace.isAbstract()); + eClass.setInterface(ace.isInterface()); + if (!ace.getExtendsIds().isEmpty() || !ace.getImplementsIds().isEmpty()) { + List allSupertypes = Stream.concat(ace.getExtendsIds().stream(), ace.getImplementsIds().stream()) + .toList(); + resolver.resolveSupertypes(eClass, allSupertypes); + } + this.ePackage.getEClassifiers().add(eClass); + return eClass; + } + + private EEnum createEEnum(final EnumEntity ee) { + final EEnum eenum = EcoreFactory.eINSTANCE.createEEnum(); + resolver.store(ee.getReferenceId(), eenum); + eenum.setName(ee.getName()); + this.ePackage.getEClassifiers().add(eenum); + return eenum; + } + + private EEnumLiteral addEEnumLiteral(final EEnum ee, final EnumEntryEntity eee, final EnumEntity eentity) { + final EEnumLiteral eenumLit = EcoreFactory.eINSTANCE.createEEnumLiteral(); + resolver.store(eee.getReferenceId(), eenumLit); + eenumLit.setName(eee.getName()); + if (eee.isHasDefaultValue()) { + if (eentity.getType().equals("int") || eentity.getType().equals("float") + || eentity.getType().equals("double")) { + int val = Double.valueOf(eee.getDefaultValue().toString()).intValue(); + eenumLit.setValue(val); + } + } + ee.getELiterals().add(eenumLit); + return eenumLit; + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/EcoreTypeResolver.java b/src/main/java/de/nexus/mmlcli/generator/EcoreTypeResolver.java index 9c8f2ae..47d1a0a 100644 --- a/src/main/java/de/nexus/mmlcli/generator/EcoreTypeResolver.java +++ b/src/main/java/de/nexus/mmlcli/generator/EcoreTypeResolver.java @@ -1,208 +1,201 @@ package de.nexus.mmlcli.generator; +import de.nexus.mmlcli.entities.instance.AttributeEntry; +import de.nexus.mmlcli.entities.instance.ObjectInstance; +import de.nexus.mmlcli.entities.instance.ReferenceEntry; +import de.nexus.mmlcli.entities.model.AttributeEntity; +import de.nexus.mmlcli.entities.model.CReferenceEntity; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.*; +import org.eclipse.emf.ecore.util.EcoreUtil; + import java.util.HashMap; import java.util.List; import java.util.Map; -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.EEnumLiteral; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.util.EcoreUtil; - -import de.nexus.mmlcli.generator.entities.instance.AttributeEntry; -import de.nexus.mmlcli.generator.entities.instance.ObjectInstance; -import de.nexus.mmlcli.generator.entities.instance.ReferenceEntry; -import de.nexus.mmlcli.generator.entities.model.AttributeEntity; -import de.nexus.mmlcli.generator.entities.model.CReferenceEntity; - /** - * The EcoreTypeResolver helps to resolve and link references in metamodels. MML replaces - * all references with unique ids. To be independent of the execution order when constructing - * the metamodel, the TypeResolver tries to resolve a reference using the id and stores the - * missing reference otherwise. When exporting the metamodel (and thus after successful complete + * The EcoreTypeResolver helps to resolve and link references in metamodels. MML replaces + * all references with unique ids. To be independent of the execution order when constructing + * the metamodel, the TypeResolver tries to resolve a reference using the id and stores the + * missing reference otherwise. When exporting the metamodel (and thus after successful complete * construction) all missing references are finally resolved. */ public class EcoreTypeResolver { - private final Map classifiers = new HashMap<>(); - private final Map references = new HashMap<>(); - private final Map attributes = new HashMap<>(); - private final Map packages = new HashMap<>(); - private final Map elits = new HashMap<>(); - private final Map unresolvedReferenceTypes = new HashMap<>(); - private final Map unresolvedReferenceOpposites = new HashMap<>(); - private final Map unresolvedAttributeEnumTypes = new HashMap<>(); - private final Map unresolvedAttributeEnumValues = new HashMap<>(); - private final Map> unresolvedSupertypes = new HashMap<>(); + private final Map classifiers = new HashMap<>(); + private final Map references = new HashMap<>(); + private final Map attributes = new HashMap<>(); + private final Map packages = new HashMap<>(); + private final Map elits = new HashMap<>(); + private final Map unresolvedReferenceTypes = new HashMap<>(); + private final Map unresolvedReferenceOpposites = new HashMap<>(); + private final Map unresolvedAttributeEnumTypes = new HashMap<>(); + private final Map unresolvedAttributeEnumValues = new HashMap<>(); + private final Map> unresolvedSupertypes = new HashMap<>(); - public void store(String classId, EClassifier classifier) { - this.classifiers.put(classId, classifier); - } + public void store(String classId, EClassifier classifier) { + this.classifiers.put(classId, classifier); + } - public void store(String refId, EReference reference) { - this.references.put(refId, reference); - } + public void store(String refId, EReference reference) { + this.references.put(refId, reference); + } - public void store(String attrId, EAttribute attibute) { - this.attributes.put(attrId, attibute); - } + public void store(String attrId, EAttribute attibute) { + this.attributes.put(attrId, attibute); + } - public void store(String pckgId, EPackage packagee) { - this.packages.put(pckgId, packagee); - } + public void store(String pckgId, EPackage packagee) { + this.packages.put(pckgId, packagee); + } - public void store(String elitId, EEnumLiteral enumLiteral) { - this.elits.put(elitId, enumLiteral); - } + public void store(String elitId, EEnumLiteral enumLiteral) { + this.elits.put(elitId, enumLiteral); + } - public void dumpResolverStorage() { - System.out.println("================[ERROR]================"); - System.out.println("==========[EcoreTypeResolver]=========="); - System.out.println("### Packages"); - for (String key : this.packages.keySet()) { - System.out.printf("\t- %s%n", key); - } - System.out.println("### Classifiers"); - for (String key : this.classifiers.keySet()) { - System.out.printf("\t- %s%n", key); - } - System.out.println("### Attributes"); - for (String key : this.attributes.keySet()) { - System.out.printf("\t- %s%n", key); - } - System.out.println("### References"); - for (String key : this.references.keySet()) { - System.out.printf("\t- %s%n", key); - } - System.out.println("### ELits"); - for (String key : this.elits.keySet()) { - System.out.printf("\t- %s%n", key); - } - System.out.println("================[ERROR]================"); - } + public void dumpResolverStorage() { + System.out.println("================[ERROR]================"); + System.out.println("==========[EcoreTypeResolver]=========="); + System.out.println("### Packages"); + for (String key : this.packages.keySet()) { + System.out.printf("\t- %s%n", key); + } + System.out.println("### Classifiers"); + for (String key : this.classifiers.keySet()) { + System.out.printf("\t- %s%n", key); + } + System.out.println("### Attributes"); + for (String key : this.attributes.keySet()) { + System.out.printf("\t- %s%n", key); + } + System.out.println("### References"); + for (String key : this.references.keySet()) { + System.out.printf("\t- %s%n", key); + } + System.out.println("### ELits"); + for (String key : this.elits.keySet()) { + System.out.printf("\t- %s%n", key); + } + System.out.println("================[ERROR]================"); + } - public void resolveSupertypes(EClass clazz, List classIds) { - this.unresolvedSupertypes.put(clazz, classIds); - } + public void resolveSupertypes(EClass clazz, List classIds) { + this.unresolvedSupertypes.put(clazz, classIds); + } - public void resolveReference(EReference ref, CReferenceEntity refEntity) { - String typeId = refEntity.getType(); - if (classifiers.containsKey(typeId)) { - ref.setEType(classifiers.get(typeId)); - } else { - unresolvedReferenceTypes.put(ref, typeId); - } + public void resolveReference(EReference ref, CReferenceEntity refEntity) { + String typeId = refEntity.getType(); + if (classifiers.containsKey(typeId)) { + ref.setEType(classifiers.get(typeId)); + } else { + unresolvedReferenceTypes.put(ref, typeId); + } - if (refEntity.isHasOpposite()) { - String oppositeId = refEntity.getOpposite(); - if (classifiers.containsKey(oppositeId)) { - ref.setEType(classifiers.get(oppositeId)); - } else { - unresolvedReferenceOpposites.put(ref, oppositeId); - } - } - } + if (refEntity.isHasOpposite()) { + String oppositeId = refEntity.getOpposite(); + if (classifiers.containsKey(oppositeId)) { + ref.setEType(classifiers.get(oppositeId)); + } else { + unresolvedReferenceOpposites.put(ref, oppositeId); + } + } + } - public void resolveAttributeEnum(EAttribute attr, AttributeEntity attrEntity) { - if (!attrEntity.isEnumType()) { - return; - } + public void resolveAttributeEnum(EAttribute attr, AttributeEntity attrEntity) { + if (!attrEntity.isEnumType()) { + return; + } - String typeId = attrEntity.getType(); - if (classifiers.containsKey(typeId)) { - attr.setEType(classifiers.get(typeId)); - } else { - unresolvedAttributeEnumTypes.put(attr, typeId); - } + String typeId = attrEntity.getType(); + if (classifiers.containsKey(typeId)) { + attr.setEType(classifiers.get(typeId)); + } else { + unresolvedAttributeEnumTypes.put(attr, typeId); + } - if (attrEntity.isHasDefaultValue()) { - String valueId = attrEntity.getDefaultValue(); - if (elits.containsKey(valueId)) { - attr.setDefaultValue(elits.get(valueId).getName()); - } else { - unresolvedAttributeEnumValues.put(attr, valueId); - } - } - } + if (attrEntity.isHasDefaultValue()) { + String valueId = attrEntity.getDefaultValue(); + if (elits.containsKey(valueId)) { + attr.setDefaultValue(elits.get(valueId).getName()); + } else { + unresolvedAttributeEnumValues.put(attr, valueId); + } + } + } - public EObject resolveObjectInstance(ObjectInstance objInst) { - EClass clazz = (EClass) this.classifiers.get(objInst.getReferenceTypeId()); - return EcoreUtil.create(clazz); - } + public EObject resolveObjectInstance(ObjectInstance objInst) { + EClass clazz = (EClass) this.classifiers.get(objInst.getReferenceTypeId()); + return EcoreUtil.create(clazz); + } - public EAttribute resolveAttribute(AttributeEntry attr) { - return this.attributes.get(attr.getTypeId()); - } + public EAttribute resolveAttribute(AttributeEntry attr) { + return this.attributes.get(attr.getTypeId()); + } - public EReference resolveReference(ReferenceEntry ref) { - return this.references.get(ref.getTypeId()); - } + public EReference resolveReference(ReferenceEntry ref) { + return this.references.get(ref.getTypeId()); + } - public EEnumLiteral resolveAttributeEnum(AttributeEntry attr) { - return this.elits.get(attr.getValue()); - } + public EEnumLiteral resolveAttributeEnum(AttributeEntry attr) { + return this.elits.get(attr.getValue()); + } - public void resolveUnresovedTypes() { - for (Map.Entry refEntry : this.unresolvedReferenceTypes.entrySet()) { - EReference ref = refEntry.getKey(); - String typeId = refEntry.getValue(); - if (classifiers.containsKey(typeId)) { - ref.setEType(classifiers.get(typeId)); - } else { - dumpResolverStorage(); - throw new IllegalArgumentException("Could not resolve classId: " + typeId); - } - } + public void resolveUnresovedTypes() { + for (Map.Entry refEntry : this.unresolvedReferenceTypes.entrySet()) { + EReference ref = refEntry.getKey(); + String typeId = refEntry.getValue(); + if (classifiers.containsKey(typeId)) { + ref.setEType(classifiers.get(typeId)); + } else { + dumpResolverStorage(); + throw new IllegalArgumentException("Could not resolve classId: " + typeId); + } + } - for (Map.Entry refEntry : this.unresolvedReferenceOpposites.entrySet()) { - EReference ref = refEntry.getKey(); - String typeId = refEntry.getValue(); - if (references.containsKey(typeId)) { - ref.setEOpposite(references.get(typeId)); - } else { - dumpResolverStorage(); - throw new IllegalArgumentException("Could not resolve referenceId: " + typeId); - } - } + for (Map.Entry refEntry : this.unresolvedReferenceOpposites.entrySet()) { + EReference ref = refEntry.getKey(); + String typeId = refEntry.getValue(); + if (references.containsKey(typeId)) { + ref.setEOpposite(references.get(typeId)); + } else { + dumpResolverStorage(); + throw new IllegalArgumentException("Could not resolve referenceId: " + typeId); + } + } - for (Map.Entry attrEntry : this.unresolvedAttributeEnumTypes.entrySet()) { - EAttribute attr = attrEntry.getKey(); - String typeId = attrEntry.getValue(); - if (classifiers.containsKey(typeId)) { - attr.setEType(classifiers.get(typeId)); - } else { - dumpResolverStorage(); - throw new IllegalArgumentException("Could not resolve enumId: " + typeId); - } - } + for (Map.Entry attrEntry : this.unresolvedAttributeEnumTypes.entrySet()) { + EAttribute attr = attrEntry.getKey(); + String typeId = attrEntry.getValue(); + if (classifiers.containsKey(typeId)) { + attr.setEType(classifiers.get(typeId)); + } else { + dumpResolverStorage(); + throw new IllegalArgumentException("Could not resolve enumId: " + typeId); + } + } - for (Map.Entry attrEntry : this.unresolvedAttributeEnumValues.entrySet()) { - EAttribute attr = attrEntry.getKey(); - String typeId = attrEntry.getValue(); - if (elits.containsKey(typeId)) { - attr.setDefaultValue(elits.get(typeId).getName()); - } else { - dumpResolverStorage(); - throw new IllegalArgumentException("Could not resolve enum valueId: " + typeId); - } - } + for (Map.Entry attrEntry : this.unresolvedAttributeEnumValues.entrySet()) { + EAttribute attr = attrEntry.getKey(); + String typeId = attrEntry.getValue(); + if (elits.containsKey(typeId)) { + attr.setDefaultValue(elits.get(typeId).getName()); + } else { + dumpResolverStorage(); + throw new IllegalArgumentException("Could not resolve enum valueId: " + typeId); + } + } - for (Map.Entry> supertypeEntry : this.unresolvedSupertypes.entrySet()) { - EClass clazz = supertypeEntry.getKey(); - List supertypeIds = supertypeEntry.getValue(); - EList superTypes = clazz.getESuperTypes(); - for (String supertypeId : supertypeIds) { - if (classifiers.containsKey(supertypeId)) { - superTypes.add((EClass) classifiers.get(supertypeId)); - } else { - dumpResolverStorage(); - throw new IllegalArgumentException("Could not resolve supertype classId: " + supertypeId); - } - } - } - } + for (Map.Entry> supertypeEntry : this.unresolvedSupertypes.entrySet()) { + EClass clazz = supertypeEntry.getKey(); + List supertypeIds = supertypeEntry.getValue(); + EList superTypes = clazz.getESuperTypes(); + for (String supertypeId : supertypeIds) { + if (classifiers.containsKey(supertypeId)) { + superTypes.add((EClass) classifiers.get(supertypeId)); + } else { + dumpResolverStorage(); + throw new IllegalArgumentException("Could not resolve supertype classId: " + supertypeId); + } + } + } + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/EmfGraphBuilderUtils.java b/src/main/java/de/nexus/mmlcli/generator/EmfGraphBuilderUtils.java index 67671b2..836f9ce 100644 --- a/src/main/java/de/nexus/mmlcli/generator/EmfGraphBuilderUtils.java +++ b/src/main/java/de/nexus/mmlcli/generator/EmfGraphBuilderUtils.java @@ -4,30 +4,44 @@ import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EcorePackage; public class EmfGraphBuilderUtils { - public static EDataType mapETypes(String mmlType) { - return switch (mmlType) { - case "string" -> EcorePackage.Literals.ESTRING; - case "float" -> EcorePackage.Literals.EFLOAT; - case "double" -> EcorePackage.Literals.EDOUBLE; - case "int" -> EcorePackage.Literals.EINT; - case "boolean" -> EcorePackage.Literals.EBOOLEAN; - default -> EcorePackage.Literals.ESTRING; - }; - } - - public static R mapVals(String mmlType, T value) { - return mapVals(mapETypes(mmlType), value); - } - - @SuppressWarnings("unchecked") - public static R mapVals(EDataType type, T value) { - return switch (type.getClassifierID()) { - case EcorePackage.ESTRING -> (R) value; - case EcorePackage.EFLOAT -> (R) Float.valueOf(value.toString()); - case EcorePackage.EDOUBLE -> (R) Double.valueOf(value.toString()); - case EcorePackage.EINT -> (R) Integer.valueOf(Double.valueOf(value.toString()).intValue()); - case EcorePackage.EBOOLEAN -> (R) Boolean.valueOf(value.toString()); - default -> (R) value.toString(); - }; - } + public static EDataType mapETypes(String mmlType) { + return switch (mmlType) { + case "string" -> EcorePackage.Literals.ESTRING; + case "float" -> EcorePackage.Literals.EFLOAT; + case "double" -> EcorePackage.Literals.EDOUBLE; + case "int" -> EcorePackage.Literals.EINT; + case "boolean" -> EcorePackage.Literals.EBOOLEAN; + default -> EcorePackage.Literals.ESTRING; + }; + } + + public static String mapETypes(EDataType dataType) { + return switch (dataType.getClassifierID()) { + case EcorePackage.EFLOAT -> "float"; + case EcorePackage.EDOUBLE -> "double"; + case EcorePackage.EINT -> "int"; + case EcorePackage.EBOOLEAN -> "boolean"; + default -> "string"; + }; + } + + public static boolean isETypeDefaultValue(EDataType type, T value) { + return type.getDefaultValue().equals(value); + } + + public static R mapVals(String mmlType, T value) { + return mapVals(mapETypes(mmlType), value); + } + + @SuppressWarnings("unchecked") + public static R mapVals(EDataType type, T value) { + return switch (type.getClassifierID()) { + case EcorePackage.ESTRING -> (R) value; + case EcorePackage.EFLOAT -> (R) Float.valueOf(value.toString()); + case EcorePackage.EDOUBLE -> (R) Double.valueOf(value.toString()); + case EcorePackage.EINT -> (R) Integer.valueOf(Double.valueOf(value.toString()).intValue()); + case EcorePackage.EBOOLEAN -> (R) Boolean.valueOf(value.toString()); + default -> (R) value.toString(); + }; + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/EmfResourceBuilder.java b/src/main/java/de/nexus/mmlcli/generator/EmfResourceBuilder.java index 27c39c4..24a1633 100644 --- a/src/main/java/de/nexus/mmlcli/generator/EmfResourceBuilder.java +++ b/src/main/java/de/nexus/mmlcli/generator/EmfResourceBuilder.java @@ -1,8 +1,10 @@ package de.nexus.mmlcli.generator; -import de.nexus.mmlcli.generator.entities.instance.GeneratorInstance; -import de.nexus.mmlcli.generator.entities.model.ModelEntity; -import de.nexus.mmlcli.generator.entities.model.PackageEntity; +import de.nexus.mmlcli.entities.instance.GeneratorInstance; +import de.nexus.mmlcli.entities.model.ModelEntity; +import de.nexus.mmlcli.entities.model.PackageEntity; +import de.nexus.mmlcli.generator.diagnostic.DocumentDiagnostic; +import de.nexus.mmlcli.generator.diagnostic.DocumentPoint; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; @@ -13,6 +15,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * The EmfResourceBuilder coordinates the export of metamodels and instance graphs. @@ -36,9 +39,20 @@ public class EmfResourceBuilder { } catch (IOException ex) { System.out.println("[MODEL PATH BUILDER] Could not create models directory: " + modelsDir); } + ArrayList seriousDiagnostics = doc.getDiagnostics().stream().filter(x -> x.getSeverity() == 1).collect(Collectors.toCollection(ArrayList::new)); + if (!seriousDiagnostics.isEmpty()) { + System.err.printf("[DOCUMENT SKIP] Skipping %s due to the following errors%n", doc.uri.toString()); + System.err.flush(); + seriousDiagnostics.forEach(diag -> { + DocumentPoint startPoint = diag.getRange().getStart(); + System.err.printf("%s (%s) starting in line %d:%d%n", diag.getMessage(), diag.getCode(), startPoint.getLine(), startPoint.getCharacter()); + System.err.flush(); + }); + continue; + } ModelEntity model = doc.getParsedGenerator().getTypegraph(); for (PackageEntity pckgEntity : model.getPackages()) { - String fileName = Path.of(doc.uri).getFileName().toString().replace(".mml", "") + "_" + String fileName = Path.of(doc.uri).getFileName().toString().replace(".mml", "").replace(".ecore", "") + "_" + pckgEntity.getName() + ".ecore"; Path filePath = Paths.get(modelsDir.toString(), fileName); String packageUri = String.format("platform:/resource/%s/model/%s", projectName, fileName); diff --git a/src/main/java/de/nexus/mmlcli/generator/SerializedDocument.java b/src/main/java/de/nexus/mmlcli/generator/SerializedDocument.java index b6e4aee..4de1159 100644 --- a/src/main/java/de/nexus/mmlcli/generator/SerializedDocument.java +++ b/src/main/java/de/nexus/mmlcli/generator/SerializedDocument.java @@ -2,20 +2,39 @@ package de.nexus.mmlcli.generator; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import de.nexus.mmlcli.generator.diagnostic.DocumentDiagnostic; import java.net.URI; +import java.util.ArrayList; +import java.util.List; public class SerializedDocument { URI uri; String content; + ArrayList diagnostics = new ArrayList<>(); - public DeserializedDocument getParsedGenerator(){ + public DeserializedDocument getParsedGenerator() { return DeserializedDocument.build(this.content); } + public SerializedDocument(URI uri, DeserializedDocument dDoc) { + Gson gson = new Gson(); + this.content = gson.toJson(dDoc); + this.uri = uri; + } + + public String serialize() { + Gson gson = new Gson(); + return gson.toJson(List.of(this)); + } + public static SerializedDocument[] deserialize(String json) { GsonBuilder builder = new GsonBuilder(); Gson gson = builder.create(); return gson.fromJson(json, SerializedDocument[].class); } + + public ArrayList getDiagnostics() { + return diagnostics; + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/XMIInstanceGraphBuilder.java b/src/main/java/de/nexus/mmlcli/generator/XMIInstanceGraphBuilder.java index 442326d..b23139b 100644 --- a/src/main/java/de/nexus/mmlcli/generator/XMIInstanceGraphBuilder.java +++ b/src/main/java/de/nexus/mmlcli/generator/XMIInstanceGraphBuilder.java @@ -1,11 +1,7 @@ package de.nexus.mmlcli.generator; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import de.nexus.mmlcli.entities.instance.AttributeEntry; +import de.nexus.mmlcli.entities.instance.ObjectInstance; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EObject; @@ -14,77 +10,77 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.xmi.XMIResource; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; -import de.nexus.mmlcli.generator.entities.instance.AttributeEntry; -import de.nexus.mmlcli.generator.entities.instance.ObjectInstance; +import java.io.IOException; +import java.util.*; /** * The XMIInstanceGraphBuilder contains all functions to generate a model instance from a ObjectInstance as an XMI file. */ public class XMIInstanceGraphBuilder { - private final ArrayList objects = new ArrayList<>(); - private final String exportPath; + private final ArrayList objects = new ArrayList<>(); + private final String exportPath; - public XMIInstanceGraphBuilder(List objInsts, String exportPath, EcoreTypeResolver typeResolver, - XMIInstanceResolver instResolver) { - objInsts.forEach(objInst -> { - EObject obj = typeResolver.resolveObjectInstance(objInst); - for (AttributeEntry attr : objInst.getAttributes()) { - setAttribute(obj, attr, typeResolver, instResolver); - } - instResolver.registerReference(objInst.getReferenceId(), objInst.getReferences()); - - this.objects.add(obj); - instResolver.store(objInst.getReferenceId(), obj); - }); - - this.exportPath = exportPath; - } + public XMIInstanceGraphBuilder(List objInsts, String exportPath, EcoreTypeResolver typeResolver, + XMIInstanceResolver instResolver) { + objInsts.forEach(objInst -> { + EObject obj = typeResolver.resolveObjectInstance(objInst); + for (AttributeEntry attr : objInst.getAttributes()) { + setAttribute(obj, attr, typeResolver, instResolver); + } + instResolver.registerReference(objInst.getReferenceId(), objInst.getReferences()); - public static void buildXmiFile(List graphBuilderList, EcoreTypeResolver typeResolver, - XMIInstanceResolver instanceResolver, ResourceSet resSet) { - instanceResolver.resolveUnresolvedReferences(typeResolver); - - Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; - Map m = reg.getExtensionToFactoryMap(); - m.put(XMIResource.XMI_NS, new XMIResourceFactoryImpl()); + this.objects.add(obj); + instResolver.store(objInst.getReferenceId(), obj); + }); - List resources = new ArrayList<>(); - // create a resource - try { - for (XMIInstanceGraphBuilder builder : graphBuilderList) { - Resource resource = resSet - .createResource(URI.createFileURI(Objects.requireNonNull(builder.exportPath))); - /* - * add your EPackage as root, everything is hierarchical included in this first - * node - */ - builder.objects.forEach(obj -> resource.getContents().add(obj)); - //System.out.println("[XMIBuilder DEBUG] Resource contains: "+resource.getContents().size()); - resources.add(resource); - } - } catch (NullPointerException e) { - e.printStackTrace(); - } + this.exportPath = exportPath; + } - // now save the content. - for (Resource resource : resources) { - try { - resource.save(Collections.EMPTY_MAP); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - - private void setAttribute(EObject obj, AttributeEntry attr,EcoreTypeResolver typeResolver, - XMIInstanceResolver instResolver) { - EAttribute eattr = typeResolver.resolveAttribute(attr); - if (attr.isEnumType()) { - obj.eSet(eattr, typeResolver.resolveAttributeEnum(attr)); - }else { - obj.eSet(eattr, EmfGraphBuilderUtils.mapVals(eattr.getEAttributeType(), attr.getValue())); - } - - } + public static void buildXmiFile(List graphBuilderList, EcoreTypeResolver typeResolver, + XMIInstanceResolver instanceResolver, ResourceSet resSet) { + instanceResolver.resolveUnresolvedReferences(typeResolver); + + Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; + Map m = reg.getExtensionToFactoryMap(); + m.put(XMIResource.XMI_NS, new XMIResourceFactoryImpl()); + + List resources = new ArrayList<>(); + // create a resource + try { + for (XMIInstanceGraphBuilder builder : graphBuilderList) { + Resource resource = resSet + .createResource(URI.createFileURI(Objects.requireNonNull(builder.exportPath))); + /* + * add your EPackage as root, everything is hierarchical included in this first + * node + */ + builder.objects.forEach(obj -> resource.getContents().add(obj)); + //System.out.println("[XMIBuilder DEBUG] Resource contains: "+resource.getContents().size()); + resources.add(resource); + } + } catch (NullPointerException e) { + e.printStackTrace(); + } + + // now save the content. + for (Resource resource : resources) { + try { + resource.save(Collections.EMPTY_MAP); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + + private void setAttribute(EObject obj, AttributeEntry attr, EcoreTypeResolver typeResolver, + XMIInstanceResolver instResolver) { + EAttribute eattr = typeResolver.resolveAttribute(attr); + if (attr.isEnumType()) { + obj.eSet(eattr, typeResolver.resolveAttributeEnum(attr)); + } else { + obj.eSet(eattr, EmfGraphBuilderUtils.mapVals(eattr.getEAttributeType(), attr.getValue())); + } + + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/XMIInstanceResolver.java b/src/main/java/de/nexus/mmlcli/generator/XMIInstanceResolver.java index 860ddfb..adc8865 100644 --- a/src/main/java/de/nexus/mmlcli/generator/XMIInstanceResolver.java +++ b/src/main/java/de/nexus/mmlcli/generator/XMIInstanceResolver.java @@ -1,54 +1,55 @@ package de.nexus.mmlcli.generator; +import de.nexus.mmlcli.entities.instance.ReferenceEntry; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; + import java.util.HashMap; import java.util.List; import java.util.Map; -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; - -import de.nexus.mmlcli.generator.entities.instance.ReferenceEntry; - /** - * XMIInstanceResolver helps to resolve and link references in instance graphs. MML replaces - * all references with unique ids. To be independent of the execution order when constructing - * the instance graph, the TypeResolver stores all missing references. Finally, when exporting - * the instance graph (and thus after successful complete construction), all missing references + * XMIInstanceResolver helps to resolve and link references in instance graphs. MML replaces + * all references with unique ids. To be independent of the execution order when constructing + * the instance graph, the TypeResolver stores all missing references. Finally, when exporting + * the instance graph (and thus after successful complete construction), all missing references * are resolved. */ public class XMIInstanceResolver { - private final Map objects = new HashMap<>(); - private final Map> unresolvedReferences = new HashMap<>(); + private final Map objects = new HashMap<>(); + private final Map> unresolvedReferences = new HashMap<>(); - public void store(String objId, EObject obj) { - this.objects.put(objId, obj); - } + public void store(String objId, EObject obj) { + this.objects.put(objId, obj); + } - public void registerReference(String objId, List references) { - this.unresolvedReferences.put(objId, references); - } + public void registerReference(String objId, List references) { + this.unresolvedReferences.put(objId, references); + } - public void resolveUnresolvedReferences(EcoreTypeResolver typeResolver) { - for (Map.Entry> entry : this.unresolvedReferences.entrySet()) { - EObject base = this.objects.get(entry.getKey()); - for (ReferenceEntry ref : entry.getValue()) { - EReference eref = typeResolver.resolveReference(ref); - if (eref.isMany()) { - @SuppressWarnings("unchecked") - EList oldVals = (EList) base.eGet(eref); - for (String refId : ref.getReferencedIds()) { - EObject target = this.objects.get(refId); - oldVals.add(target); - } - } else { - if (!ref.getReferencedIds().isEmpty()) { - String refId = ref.getReferencedIds().get(0); - EObject target = this.objects.get(refId); - base.eSet(eref, target); - } - } - } - } - } + public void resolveUnresolvedReferences(EcoreTypeResolver typeResolver) { + for (Map.Entry> entry : this.unresolvedReferences.entrySet()) { + EObject base = this.objects.get(entry.getKey()); + for (ReferenceEntry ref : entry.getValue()) { + EReference eref = typeResolver.resolveReference(ref); + if (eref.isMany()) { + @SuppressWarnings("unchecked") + EList oldVals = (EList) base.eGet(eref); + for (String refId : ref.getReferencedIds()) { + EObject target = this.objects.get(refId); + if (!oldVals.contains(target)) { + oldVals.add(target); + } + } + } else { + if (!ref.getReferencedIds().isEmpty()) { + String refId = ref.getReferencedIds().get(0); + EObject target = this.objects.get(refId); + base.eSet(eref, target); + } + } + } + } + } } diff --git a/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentDiagnostic.java b/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentDiagnostic.java new file mode 100644 index 0000000..2aa6513 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentDiagnostic.java @@ -0,0 +1,29 @@ +package de.nexus.mmlcli.generator.diagnostic; + +public class DocumentDiagnostic { + private String message; + private DocumentRange range; + private int severity; + private String code; + private String source; + + public String getMessage() { + return message; + } + + public DocumentRange getRange() { + return range; + } + + public int getSeverity() { + return severity; + } + + public String getCode() { + return code; + } + + public String getSource() { + return source; + } +} diff --git a/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentPoint.java b/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentPoint.java new file mode 100644 index 0000000..618db78 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentPoint.java @@ -0,0 +1,14 @@ +package de.nexus.mmlcli.generator.diagnostic; + +public class DocumentPoint { + private int character; + private int line; + + public int getCharacter() { + return character; + } + + public int getLine() { + return line; + } +} diff --git a/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentRange.java b/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentRange.java new file mode 100644 index 0000000..758d413 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/generator/diagnostic/DocumentRange.java @@ -0,0 +1,14 @@ +package de.nexus.mmlcli.generator.diagnostic; + +public class DocumentRange { + private DocumentPoint start; + private DocumentPoint end; + + public DocumentPoint getStart() { + return start; + } + + public DocumentPoint getEnd() { + return end; + } +} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/instance/AttributeEntry.java b/src/main/java/de/nexus/mmlcli/generator/entities/instance/AttributeEntry.java deleted file mode 100644 index 8155bd6..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/instance/AttributeEntry.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.nexus.mmlcli.generator.entities.instance; - -/** - * Dataclass for an instance attribute - */ -public class AttributeEntry { - private String name; - private String typeId; - private T value; - private boolean isEnumType; - - public String getTypeId() { - return typeId; - } - - public String getName() { - return name; - } - - public T getValue() { - return value; - } - - public boolean isEnumType() { - return isEnumType; - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/instance/GeneratorInstance.java b/src/main/java/de/nexus/mmlcli/generator/entities/instance/GeneratorInstance.java deleted file mode 100644 index 1fd593f..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/instance/GeneratorInstance.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.nexus.mmlcli.generator.entities.instance; - -import java.util.ArrayList; - -/** - * Dataclass for a generator of a single XMI file - */ -public class GeneratorInstance { - private String instanceName; - private ArrayList instances; - - public String getInstanceName() { - return instanceName; - } - - public ArrayList getInstances() { - return instances; - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/instance/GeneratorInstanceWrapper.java b/src/main/java/de/nexus/mmlcli/generator/entities/instance/GeneratorInstanceWrapper.java deleted file mode 100644 index e4b8ade..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/instance/GeneratorInstanceWrapper.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.nexus.mmlcli.generator.entities.instance; - -import java.util.ArrayList; - -/** - * Dataclass for list of generators for multiple XMI files - */ -public class GeneratorInstanceWrapper { - private ArrayList serializedInstances; - - public ArrayList getSerializedInstances() { - return serializedInstances; - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/instance/ObjectInstance.java b/src/main/java/de/nexus/mmlcli/generator/entities/instance/ObjectInstance.java deleted file mode 100644 index 0e6d238..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/instance/ObjectInstance.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.nexus.mmlcli.generator.entities.instance; - -import java.util.ArrayList; - -/** - * Dataclass for an instance - */ -public class ObjectInstance { - private String referenceId; - private String referenceTypeId; - private String name; - private ArrayList> attributes; - private ArrayList references; - - public String getReferenceId() { - return referenceId; - } - - public String getReferenceTypeId() { - return referenceTypeId; - } - - public String getName() { - return name; - } - - public ArrayList> getAttributes() { - return attributes; - } - - public ArrayList getReferences() { - return references; - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/instance/ReferenceEntry.java b/src/main/java/de/nexus/mmlcli/generator/entities/instance/ReferenceEntry.java deleted file mode 100644 index 3ecbbb3..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/instance/ReferenceEntry.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.nexus.mmlcli.generator.entities.instance; - -import java.util.ArrayList; - -/** - * Dataclass for an instance reference - */ -public class ReferenceEntry { - private String name; - private String typeId; - private ArrayList referencedIds; - - public String getName() { - return name; - } - - public String getTypeId() { - return typeId; - } - - public ArrayList getReferencedIds() { - return referencedIds; - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/AbstractClassEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/AbstractClassEntity.java deleted file mode 100644 index 6cfb71d..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/AbstractClassEntity.java +++ /dev/null @@ -1,60 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -import java.util.ArrayList; -import java.util.stream.Collectors; - -/*** - * Dataclass for a class-like (Abstract class, class or interface) - */ -public class AbstractClassEntity { - private String referenceId; - private String name; - private boolean isAbstract; - private boolean isInterface; - private final ArrayList> attributes = new ArrayList<>(); - private final ArrayList references = new ArrayList<>(); - private final ArrayList extendsIds = new ArrayList<>(); - private final ArrayList implementsIds = new ArrayList<>(); - - public String getReferenceId() { - return referenceId; - } - - public String getName() { - return name; - } - - public boolean isAbstract() { - return isAbstract; - } - - public boolean isInterface() { - return isInterface; - } - - public ArrayList> getAttributes() { - return attributes; - } - - public ArrayList getReferences() { - return references; - } - - public ArrayList getExtendsIds() { - return extendsIds; - } - - public ArrayList getImplementsIds() { - return implementsIds; - } - - @Override - public String toString() { - String attributeString = attributes.isEmpty() ? "" - : "\n" + attributes.stream().map(AttributeEntity::toString).collect(Collectors.joining(",")) + "\n"; - String referenceString = references.isEmpty() ? "" - : "\n" + references.stream().map(CReferenceEntity::toString).collect(Collectors.joining(",")) + "\n"; - return String.format("%s(isAbstract:%b|isInterface:%b||%s||%s)", name, isAbstract, isInterface, attributeString, - referenceString); - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/AttributeEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/AttributeEntity.java deleted file mode 100644 index a5d6f62..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/AttributeEntity.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -/** - * Dataclass for a class attribute - */ -public class AttributeEntity { - private String referenceId; - private String name; - private String type; - private boolean isEnumType; - private boolean hasDefaultValue; - private T defaultValue; - private ClassElementModifiers modifiers; - - public String getReferenceId() { - return referenceId; - } - - public String getName() { - return name; - } - - public String getType() { - return type; - } - - public boolean isEnumType() { - return isEnumType; - } - - public boolean isHasDefaultValue() { - return hasDefaultValue; - } - - public T getDefaultValue() { - return defaultValue; - } - - public ClassElementModifiers getModifiers() { - return modifiers; - } - - @Override - public String toString() { - return String.format("%s<%s>", name, type); - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/CReferenceEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/CReferenceEntity.java deleted file mode 100644 index 97d2600..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/CReferenceEntity.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -/** - * Dataclass for class references - */ -public class CReferenceEntity { - private String referenceId; - private String name; - private MultiplicityEntity multiplicity; - private String type; - private ClassElementModifiers modifiers; - private boolean hasOpposite; - private String opposite; - - public String getReferenceId() { - return referenceId; - } - - public String getName() { - return name; - } - - public MultiplicityEntity getMultiplicity() { - return multiplicity; - } - - public String getType() { - return type; - } - - public ClassElementModifiers getModifiers() { - return modifiers; - } - - public boolean isHasOpposite() { - return hasOpposite; - } - - public String getOpposite() { - return opposite; - } - - @Override - public String toString() { - return String.format("(%s -> %s)", name, type); - } - -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/ClassElementModifiers.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/ClassElementModifiers.java deleted file mode 100644 index 968048a..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/ClassElementModifiers.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -import com.google.gson.annotations.SerializedName; - -/** - * Dataclass for class modifiers - */ -public class ClassElementModifiers { - private boolean readonly; - @SerializedName("volatile") - private boolean _volatile; - @SerializedName("transient") - private boolean _transient; - private boolean unsettable; - private boolean derived; - private boolean unique; - private boolean ordered; - private boolean resolve; - private boolean id; - - public boolean isReadonly() { - return readonly; - } - - public boolean isVolatile() { - return _volatile; - } - - public boolean isTransient() { - return _transient; - } - - public boolean isUnsettable() { - return unsettable; - } - - public boolean isDerived() { - return derived; - } - - public boolean isUnique() { - return unique; - } - - public boolean isOrdered() { - return ordered; - } - - public boolean isResolve() { - return resolve; - } - - public boolean isId() { - return id; - } - -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/EnumEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/EnumEntity.java deleted file mode 100644 index a5fad50..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/EnumEntity.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -import java.util.ArrayList; -import java.util.stream.Collectors; - -/** - * Dataclass for a enum - */ -public class EnumEntity { - private String referenceId; - private String name; - private String type; - private ArrayList> entries; - - public String getReferenceId() { - return referenceId; - } - - public String getName() { - return name; - } - - public String getType() { - return type; - } - - public ArrayList> getEntries() { - return entries; - } - - @Override - public String toString() { - return String.format("ENUM<%s,%s>{%s}", name, type, entries.isEmpty() ? "" - : entries.stream().map(EnumEntryEntity::toString).collect(Collectors.joining(","))); - } -} \ No newline at end of file diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/EnumEntryEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/EnumEntryEntity.java deleted file mode 100644 index 1c0df42..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/EnumEntryEntity.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -/** - * Dataclass for a single enum entry - */ -public class EnumEntryEntity { - private String referenceId; - private String name; - private boolean hasDefaultValue; - private T defaultValue; - - public String getReferenceId() { - return referenceId; - } - - public String getName() { - return name; - } - - public boolean isHasDefaultValue() { - return hasDefaultValue; - } - - public T getDefaultValue() { - return defaultValue; - } - - @Override - public String toString() { - return String.format("[%s|%b]", name, hasDefaultValue); - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/ModelEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/ModelEntity.java deleted file mode 100644 index f242ec7..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/ModelEntity.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -import java.util.ArrayList; -import java.util.stream.Collectors; - -/** - * Dataclass for a complete metamodel - */ -public class ModelEntity { - private final ArrayList packages = new ArrayList<>(); - - public ArrayList getPackages() { - return packages; - } - - @Override - public String toString() { - return packages.isEmpty() ? "" - : "\n" + packages.stream().map(PackageEntity::toString).collect(Collectors.joining(",")) + "\n"; - } -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/MultiplicityEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/MultiplicityEntity.java deleted file mode 100644 index 7d95342..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/MultiplicityEntity.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -/** - * Dataclass for reference multiplicities - */ -public class MultiplicityEntity { - private boolean hasUpperBound; - private boolean lowerIsN; - private boolean lowerIsN0; - private boolean upperIsN; - private boolean upperIsN0; - private int lower; - private int upper; - - public boolean isHasUpperBound() { - return hasUpperBound; - } - - public boolean isLowerIsN() { - return lowerIsN; - } - - public boolean isLowerIsN0() { - return lowerIsN0; - } - - public boolean isUpperIsN() { - return upperIsN; - } - - public boolean isUpperIsN0() { - return upperIsN0; - } - - public int getLower() { - return lower; - } - - public int getUpper() { - return upper; - } - -} diff --git a/src/main/java/de/nexus/mmlcli/generator/entities/model/PackageEntity.java b/src/main/java/de/nexus/mmlcli/generator/entities/model/PackageEntity.java deleted file mode 100644 index a05b621..0000000 --- a/src/main/java/de/nexus/mmlcli/generator/entities/model/PackageEntity.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.nexus.mmlcli.generator.entities.model; - -import java.util.ArrayList; -import java.util.stream.Collectors; - -/** - * Dataclass for a package - */ -public class PackageEntity { - private String referenceId; - private String name; - private ArrayList abstractClasses; - private ArrayList> enums; - private ArrayList subPackages; - - public String getReferenceId() { - return referenceId; - } - - public String getName() { - return name; - } - - public ArrayList getAbstractClasses() { - return abstractClasses; - } - - public ArrayList> getEnums() { - return enums; - } - - public ArrayList getSubPackages() { - return subPackages; - } - - @Override - public String toString() { - String classesString = abstractClasses.isEmpty() ? "" - : "\n" + abstractClasses.stream().map(AbstractClassEntity::toString).collect(Collectors.joining(",")) - + "\n"; - String enumsString = enums.isEmpty() ? "" - : "\n" + enums.stream().map(EnumEntity::toString).collect(Collectors.joining(",")) + "\n"; - String subPackagesString = subPackages.isEmpty() ? "" - : "\n" + subPackages.stream().map(PackageEntity::toString).collect(Collectors.joining(",")) + "\n"; - return String.format("%s{%s %s %s}", name, classesString, enumsString, subPackagesString); - } -} diff --git a/src/main/java/de/nexus/mmlcli/serializer/EcoreIdResolver.java b/src/main/java/de/nexus/mmlcli/serializer/EcoreIdResolver.java new file mode 100644 index 0000000..9cfe544 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/serializer/EcoreIdResolver.java @@ -0,0 +1,21 @@ +package de.nexus.mmlcli.serializer; + +import org.eclipse.emf.ecore.ENamedElement; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class EcoreIdResolver { + private final Map elementMapping = new HashMap<>(); + + + public UUID resolveId(ENamedElement classifier) { + UUID resolved = this.elementMapping.get(classifier); + if (resolved == null) { + resolved = UUID.randomUUID(); + this.elementMapping.put(classifier, resolved); + } + return resolved; + } +} diff --git a/src/main/java/de/nexus/mmlcli/serializer/EmfResourceLoader.java b/src/main/java/de/nexus/mmlcli/serializer/EmfResourceLoader.java new file mode 100644 index 0000000..d7aa5aa --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/serializer/EmfResourceLoader.java @@ -0,0 +1,51 @@ +package de.nexus.mmlcli.serializer; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.BasicExtendedMetaData; +import org.eclipse.emf.ecore.util.ExtendedMetaData; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl; + +import java.io.File; + +public class EmfResourceLoader { + public static EPackage loadEmfResources(File ecoreFile) { + System.out.println("Serialize model"); + System.out.println("==========[Loading resources]=========="); + + // Create a resource set. + ResourceSet resourceSet = new ResourceSetImpl(); + + // Register the default resource factory -- only needed for stand-alone! + resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put( + "ecore", new EcoreResourceFactoryImpl()); + + // enable extended metadata + final ExtendedMetaData extendedMetaData = new BasicExtendedMetaData(resourceSet.getPackageRegistry()); + resourceSet.getLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, + extendedMetaData); + + // Register the package -- only needed for stand-alone! + EcorePackage ecorePackage = EcorePackage.eINSTANCE; + + // Get the URI of the model file. + URI fileURI = URI.createFileURI(ecoreFile.getAbsolutePath()); + + // Demand load the resource for this file. + Resource resource = resourceSet.getResource(fileURI, true); + + EObject eObject = resource.getContents().get(0); + if (eObject instanceof EPackage ePackage) { + resourceSet.getPackageRegistry().put(ePackage.getNsURI(), ePackage); + System.out.println("[Package ]" + ePackage.getName() + " | " + ePackage.getNsURI()); + return ePackage; + } + throw new IllegalStateException("Could not load package from ecore!"); + } +} diff --git a/src/main/java/de/nexus/mmlcli/serializer/MmlSerializedGenerator.java b/src/main/java/de/nexus/mmlcli/serializer/MmlSerializedGenerator.java new file mode 100644 index 0000000..67ccfcd --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/serializer/MmlSerializedGenerator.java @@ -0,0 +1,23 @@ +package de.nexus.mmlcli.serializer; + +import de.nexus.mmlcli.entities.model.ModelEntity; +import de.nexus.mmlcli.entities.model.PackageEntity; +import de.nexus.mmlcli.generator.DeserializedDocument; +import de.nexus.mmlcli.generator.SerializedDocument; +import org.eclipse.emf.ecore.EPackage; + +import java.net.URI; + +public class MmlSerializedGenerator { + public static PackageEntity buildEntities(EPackage pckg) { + EcoreIdResolver resolver = new EcoreIdResolver(); + return PackageEntity.fromEPackage(pckg, resolver); + } + + public static String serializeEntities(PackageEntity pckgEntity, URI uri) { + ModelEntity model = ModelEntity.fromPackageEntity(pckgEntity); + DeserializedDocument dDoc = DeserializedDocument.build(model); + SerializedDocument sDoc = new SerializedDocument(uri, dDoc); + return sDoc.serialize(); + } +} diff --git a/src/main/java/de/nexus/mmlcli/serializer/SerializeCommand.java b/src/main/java/de/nexus/mmlcli/serializer/SerializeCommand.java new file mode 100644 index 0000000..702c704 --- /dev/null +++ b/src/main/java/de/nexus/mmlcli/serializer/SerializeCommand.java @@ -0,0 +1,49 @@ +package de.nexus.mmlcli.serializer; + +import de.nexus.mmlcli.entities.model.PackageEntity; +import org.eclipse.emf.ecore.EPackage; +import picocli.CommandLine; + +import java.io.File; +import java.nio.file.Files; +import java.util.concurrent.Callable; + +@CommandLine.Command(name = "serialize", mixinStandardHelpOptions = true, version = "v1.0.0", description = "Serializes a given Ecore") +public class SerializeCommand implements Callable { + @CommandLine.Option(names = {"-o", "--out"}, paramLabel = "SERIALIZED", description = "path where the serialized model should be stored", arity = "0..1") + File serializedTarget; + + @CommandLine.Parameters(index = "0") + File ecoreFile; + + + @Override + public Integer call() throws Exception { + if (!ecoreFile.exists()) { + System.err.println("Inputfile does not exist: " + ecoreFile.getAbsolutePath()); + return 2; + } + if (!ecoreFile.canRead()) { + System.err.println("Could not read inputfile: " + ecoreFile.getAbsolutePath()); + return 2; + } + EPackage ePackage = EmfResourceLoader.loadEmfResources(ecoreFile); + PackageEntity packageEntity = MmlSerializedGenerator.buildEntities(ePackage); + String serialized = MmlSerializedGenerator.serializeEntities(packageEntity, ecoreFile.toURI()); + + if (serializedTarget == null) { + System.out.println("=$MML-CONTENT-START$="); + System.out.println(serialized); + } else { + try { + Files.writeString(serializedTarget.toPath(), serialized); + System.out.println("Written serialized file to: " + serializedTarget.getAbsolutePath()); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Could not write serialized file: " + serializedTarget.getAbsolutePath()); + return 2; + } + } + return 0; + } +} diff --git a/src/test/data/CarOwnership.ecore b/src/test/data/CarOwnership.ecore new file mode 100644 index 0000000..d473b04 --- /dev/null +++ b/src/test/data/CarOwnership.ecore @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/src/test/data/CarOwnership.json b/src/test/data/CarOwnership.json new file mode 100644 index 0000000..0f345c5 --- /dev/null +++ b/src/test/data/CarOwnership.json @@ -0,0 +1 @@ +[{"uri":"file:///c%3A/Users/Janik/Desktop/MT_Examples/CarOwnership.mml","content":"{\"typegraph\":{\"packages\":[{\"abstractClasses\":[{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlAttribute/packages@0/body@0/body@0\",\"name\":\"alter\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@0/body@2\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@0/body@1\",\"name\":\"kinder\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":true,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":true},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlClass/packages@0/body@0\"},{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@0/body@1\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@0/body@2\",\"name\":\"eltern\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":2,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlClass/packages@0/body@0\"},{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@1/body@4\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@0/body@3\",\"name\":\"autos\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":true,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":true},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlClass/packages@0/body@1\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlClass/packages@0/body@0\",\"name\":\"Person\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlAttribute/packages@0/body@1/body@0\",\"name\":\"kennzeichen\",\"type\":\"string\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlAttribute/packages@0/body@1/body@1\",\"name\":\"marke\",\"type\":\"string\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlAttribute/packages@0/body@1/body@2\",\"name\":\"erstzulassung\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlAttribute/packages@0/body@1/body@3\",\"name\":\"baujahr\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@0/body@3\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlCReference/packages@0/body@1/body@4\",\"name\":\"besitzer\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":1,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlClass/packages@0/body@0\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlClass/packages@0/body@1\",\"name\":\"Auto\",\"isInterface\":false,\"isAbstract\":false}],\"enums\":[],\"subPackages\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/CarOwnership.mmlPackage/packages@0\",\"name\":\"CarOwnership\"}]},\"instancegraph\":{\"serializedInstances\":[]}}","diagnostics":[]}] \ No newline at end of file diff --git a/src/test/data/FerrymanProblem.ecore b/src/test/data/FerrymanProblem.ecore new file mode 100644 index 0000000..19b49df --- /dev/null +++ b/src/test/data/FerrymanProblem.ecore @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/test/data/FerrymanProblem.json b/src/test/data/FerrymanProblem.json new file mode 100644 index 0000000..7f6f49c --- /dev/null +++ b/src/test/data/FerrymanProblem.json @@ -0,0 +1 @@ +[{"uri":"file:///c%3A/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mml","content":"{\"typegraph\":{\"packages\":[{\"abstractClasses\":[{\"attributes\":[],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlCReference/packages@0/body@0/body@0\",\"name\":\"leftBank\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":1,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@1\"},{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlCReference/packages@0/body@0/body@1\",\"name\":\"rightBank\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":1,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@1\"},{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlCReference/packages@0/body@0/body@2\",\"name\":\"subjects\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@2\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@0\",\"name\":\"Model\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@1\",\"name\":\"Bank\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlCReference/packages@0/body@2/body@0\",\"name\":\"isAt\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":1,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@1\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@2\",\"name\":\"Subject\",\"isInterface\":false,\"isAbstract\":true},{\"attributes\":[],\"references\":[],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@2\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@3\",\"name\":\"FerryMan\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlCReference/packages@0/body@4/body@0\",\"name\":\"likesToEat\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":false,\"ordered\":false,\"resolve\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@4\"}],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@2\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@4\",\"name\":\"Thing\",\"isInterface\":false,\"isAbstract\":true},{\"attributes\":[],\"references\":[],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@4\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@5\",\"name\":\"Wolf\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@4\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@6\",\"name\":\"Goat\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@4\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlClass/packages@0/body@7\",\"name\":\"Cabbage\",\"isInterface\":false,\"isAbstract\":false}],\"enums\":[],\"subPackages\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/FerrymanProblem.mmlPackage/packages@0\",\"name\":\"FerrymanProblem\"}]},\"instancegraph\":{\"serializedInstances\":[]}}","diagnostics":[{"message":"Reference opposite is not defined!","range":{"start":{"character":26,"line":2},"end":{"character":34,"line":2}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":26,"line":3},"end":{"character":35,"line":3}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":29,"line":4},"end":{"character":37,"line":4}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":26,"line":9},"end":{"character":30,"line":9}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":27,"line":14},"end":{"character":37,"line":14}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"}]}] \ No newline at end of file diff --git a/src/test/data/HospitalExample.ecore b/src/test/data/HospitalExample.ecore new file mode 100644 index 0000000..36799a5 --- /dev/null +++ b/src/test/data/HospitalExample.ecore @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/data/HospitalExample.json b/src/test/data/HospitalExample.json new file mode 100644 index 0000000..2433d82 --- /dev/null +++ b/src/test/data/HospitalExample.json @@ -0,0 +1 @@ +[{"uri":"file:///c%3A/Users/Janik/Desktop/MT_Examples/HospitalExample.mml","content":"{\"typegraph\":{\"packages\":[{\"abstractClasses\":[{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@1/body@0\",\"name\":\"id\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@1/body@1\",\"name\":\"reception\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":true,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":1,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@2\"},{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@1/body@2\",\"name\":\"staff\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":false,\"resolve\":true,\"containment\":true,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@3\"},{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@1/body@3\",\"name\":\"department\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":true,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@6\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@1\",\"name\":\"Hospital\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@2/body@0\",\"name\":\"waits\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":true,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@7\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@2\",\"name\":\"Reception\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@3/body@0\",\"name\":\"staffID\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":true,\"defaultValue\":-1,\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@3/body@1\",\"name\":\"name\",\"type\":\"string\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@6/body@3\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@3/body@2\",\"name\":\"works\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":true,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":0,\"upper\":1,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@6\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@3\",\"name\":\"Staff\",\"isInterface\":false,\"isAbstract\":true},{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@4/body@0\",\"name\":\"patientCapacity\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@7/body@3\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@4/body@1\",\"name\":\"caresfor\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@7\"}],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@3\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@4\",\"name\":\"Doctor\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[],\"references\":[{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@8/body@3\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@5/body@0\",\"name\":\"responsible\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":true,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":0,\"upper\":1,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@8\"}],\"extendsIds\":[\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@3\"],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@5\",\"name\":\"Nurse\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@6/body@0\",\"name\":\"dID\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":true,\"defaultValue\":-1,\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":true}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@6/body@1\",\"name\":\"maxRoomCount\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@6/body@2\",\"name\":\"rooms\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":true,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@8\"},{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@3/body@2\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@6/body@3\",\"name\":\"staff\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@3\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@6\",\"name\":\"Department\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@7/body@0\",\"name\":\"patientID\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":true,\"defaultValue\":-1,\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@7/body@1\",\"name\":\"name\",\"type\":\"string\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@7/body@2\",\"name\":\"level\",\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnum/packages@0/body@0\",\"isEnumType\":true,\"hasDefaultValue\":true,\"defaultValue\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnumEntry/packages@0/body@0/entries@3\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@4/body@1\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@7/body@3\",\"name\":\"doctor\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":false,\"lower\":1,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@4\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@7\",\"name\":\"Patient\",\"isInterface\":false,\"isAbstract\":false},{\"attributes\":[{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@8/body@0\",\"name\":\"capacity\",\"type\":\"int\",\"isEnumType\":false,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}},{\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlAttribute/packages@0/body@8/body@1\",\"name\":\"level\",\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnum/packages@0/body@0\",\"isEnumType\":true,\"hasDefaultValue\":false,\"defaultValue\":\"\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false}}],\"references\":[{\"hasOpposite\":false,\"opposite\":\"\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@8/body@2\",\"name\":\"lies\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":true,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@7\"},{\"hasOpposite\":true,\"opposite\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@5/body@0\",\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlCReference/packages@0/body@8/body@3\",\"name\":\"nurses\",\"modifiers\":{\"readonly\":false,\"volatile\":false,\"transient\":false,\"unsettable\":false,\"derived\":false,\"unique\":true,\"ordered\":true,\"resolve\":true,\"containment\":false,\"id\":false},\"multiplicity\":{\"hasUpperBound\":false,\"lowerIsN\":false,\"lowerIsN0\":true,\"lower\":0,\"upper\":0,\"upperIsN\":false,\"upperIsN0\":false},\"type\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@5\"}],\"extendsIds\":[],\"implementsIds\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlClass/packages@0/body@8\",\"name\":\"Room\",\"isInterface\":false,\"isAbstract\":false}],\"enums\":[{\"entries\":[{\"hasDefaultValue\":true,\"defaultValue\":0,\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnumEntry/packages@0/body@0/entries@0\",\"name\":\"WEAK\"},{\"hasDefaultValue\":true,\"defaultValue\":1,\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnumEntry/packages@0/body@0/entries@1\",\"name\":\"MEDIUM\"},{\"hasDefaultValue\":true,\"defaultValue\":2,\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnumEntry/packages@0/body@0/entries@2\",\"name\":\"STRONG\"},{\"hasDefaultValue\":true,\"defaultValue\":3,\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnumEntry/packages@0/body@0/entries@3\",\"name\":\"PENDING\"}],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlEnum/packages@0/body@0\",\"name\":\"Carelevel\",\"type\":\"int\"}],\"subPackages\":[],\"referenceId\":\"/c:/Users/Janik/Desktop/MT_Examples/HospitalExample.mmlPackage/packages@0\",\"name\":\"HospitalExample\"}]},\"instancegraph\":{\"serializedInstances\":[]}}","diagnostics":[{"message":"Reference opposite is not defined!","range":{"start":{"character":47,"line":9},"end":{"character":56,"line":9}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":43,"line":10},"end":{"character":48,"line":10}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":48,"line":11},"end":{"character":58,"line":11}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":45,"line":14},"end":{"character":50,"line":14}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":42,"line":34},"end":{"character":47,"line":34}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"},{"message":"Reference opposite is not defined!","range":{"start":{"character":45,"line":48},"end":{"character":49,"line":48}},"severity":4,"code":"opposite-annotation-missing","source":"model-modeling-language"}]}] \ No newline at end of file diff --git a/src/test/java/GeneratorTests.java b/src/test/java/GeneratorTests.java new file mode 100644 index 0000000..947638b --- /dev/null +++ b/src/test/java/GeneratorTests.java @@ -0,0 +1,40 @@ +import de.nexus.mmlcli.generator.EmfResourceBuilder; +import de.nexus.mmlcli.generator.SerializedDocument; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; + +public class GeneratorTests { + private final static File TEST_DATA_FOLDER = new File("src/test/data"); + + static Stream testBundleProvider() { + return TestUtils.getTestBundles(TEST_DATA_FOLDER).stream(); + } + + @ParameterizedTest + @MethodSource("testBundleProvider") + void testCorrectEcoreGeneration(TestBundle bundle, @TempDir File workingDir) throws IOException { + String serializedContent = Files.readString(bundle.getSerializedFile().toPath()); + + SerializedDocument[] result = Objects.requireNonNull(SerializedDocument.deserialize(serializedContent)); + EmfResourceBuilder.buildEmfResources(result, bundle.getBundleName(), workingDir); + + String ecoreContent = Files.readString(bundle.getEcoreFile().toPath()); + + Path generatedEcore = workingDir.toPath().resolve("model").resolve(bundle.getBundleName() + "_" + bundle.getBundleName() + ".ecore"); + + Assertions.assertTrue(generatedEcore.toFile().exists()); + + String generatedEcoreContent = Files.readString(generatedEcore); + + Assertions.assertEquals(ecoreContent, generatedEcoreContent); + } +} diff --git a/src/test/java/TestBundle.java b/src/test/java/TestBundle.java new file mode 100644 index 0000000..099de23 --- /dev/null +++ b/src/test/java/TestBundle.java @@ -0,0 +1,25 @@ +import java.io.File; + +public class TestBundle { + private final String bundleName; + private final File ecoreFile; + private final File serializedFile; + + public TestBundle(String bundleName, File ecoreFile, File serializedFile) { + this.bundleName = bundleName; + this.ecoreFile = ecoreFile; + this.serializedFile = serializedFile; + } + + public String getBundleName() { + return bundleName; + } + + public File getEcoreFile() { + return ecoreFile; + } + + public File getSerializedFile() { + return serializedFile; + } +} diff --git a/src/test/java/TestUtils.java b/src/test/java/TestUtils.java new file mode 100644 index 0000000..3b9445b --- /dev/null +++ b/src/test/java/TestUtils.java @@ -0,0 +1,51 @@ +import org.apache.commons.io.FilenameUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public class TestUtils { + public static ArrayList getTestBundles(File dataFolder) { + if (dataFolder == null || !dataFolder.exists() || !dataFolder.isDirectory()) { + throw new IllegalArgumentException("Data folder is not directory or does not exist!"); + } + + Set knownFilenames = new HashSet<>(); + ArrayList testBundles = new ArrayList<>(); + + for (File file : Objects.requireNonNull(dataFolder.listFiles())) { + String fileName = FilenameUtils.getBaseName(file.getName()); + String extension = FilenameUtils.getExtension(file.getName()); + + if (knownFilenames.contains(fileName)) { + continue; + } + knownFilenames.add(fileName); + + File ecoreFile, jsonFile; + + if (extension.equals("ecore")) { + ecoreFile = file; + jsonFile = file.toPath().resolveSibling(fileName + ".json").toFile(); + if (!jsonFile.exists() || jsonFile.isDirectory()) { + System.err.println("Skipping file due to missing json match: " + file.getAbsolutePath()); + continue; + } + } else if (extension.equals("json")) { + ecoreFile = file.toPath().resolveSibling(fileName + ".ecore").toFile(); + jsonFile = file; + if (!ecoreFile.exists() || ecoreFile.isDirectory()) { + System.err.println("Skipping file due to missing ecore match: " + file.getAbsolutePath()); + continue; + } + } else { + System.err.println("Skipping file due to extension mismatch: " + file.getAbsolutePath()); + continue; + } + testBundles.add(new TestBundle(fileName, ecoreFile, jsonFile)); + } + return testBundles; + } +} diff --git a/src/test/java/TwoWayEcoreTests.java b/src/test/java/TwoWayEcoreTests.java new file mode 100644 index 0000000..5537194 --- /dev/null +++ b/src/test/java/TwoWayEcoreTests.java @@ -0,0 +1,46 @@ +import de.nexus.mmlcli.entities.model.PackageEntity; +import de.nexus.mmlcli.generator.EmfResourceBuilder; +import de.nexus.mmlcli.generator.SerializedDocument; +import de.nexus.mmlcli.serializer.EmfResourceLoader; +import de.nexus.mmlcli.serializer.MmlSerializedGenerator; +import org.eclipse.emf.ecore.EPackage; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; + +public class TwoWayEcoreTests { + private final static File TEST_DATA_FOLDER = new File("src/test/data"); + + static Stream testBundleProvider() { + return TestUtils.getTestBundles(TEST_DATA_FOLDER).stream(); + } + + @ParameterizedTest + @MethodSource("testBundleProvider") + void testCorrectTwowaySerialization(TestBundle bundle, @TempDir File workingDir) throws IOException { + EPackage ePackage = EmfResourceLoader.loadEmfResources(bundle.getEcoreFile()); + PackageEntity packageEntity = MmlSerializedGenerator.buildEntities(ePackage); + String generatedSerialization = MmlSerializedGenerator.serializeEntities(packageEntity, bundle.getEcoreFile().toURI()); + + SerializedDocument[] result = Objects.requireNonNull(SerializedDocument.deserialize(generatedSerialization)); + EmfResourceBuilder.buildEmfResources(result, bundle.getBundleName(), workingDir); + + String ecoreContent = Files.readString(bundle.getEcoreFile().toPath()); + + Path generatedEcore = workingDir.toPath().resolve("model").resolve(bundle.getBundleName() + "_" + bundle.getBundleName() + ".ecore"); + + Assertions.assertTrue(generatedEcore.toFile().exists()); + + String generatedEcoreContent = Files.readString(generatedEcore); + + Assertions.assertEquals(ecoreContent, generatedEcoreContent); + } +}