diff --git a/.gitignore b/.gitignore
index e872dd4040..346ebb1b5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -107,4 +107,8 @@ tmp/
.gradletasknamecache
# polygot
-*.polyglot.META-INF
\ No newline at end of file
+*.polyglot.META-INF
+
+# FluentAPI
+/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.*/metamodel/
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.classpath b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.classpath
new file mode 100644
index 0000000000..bbfe5b0e61
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.project b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.project
new file mode 100644
index 0000000000..d3979f624d
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.project
@@ -0,0 +1,28 @@
+
+
+ cipm.consistency.fluentapi.java
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.settings/org.eclipse.jdt.core.prefs b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..c9545f06a4
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/META-INF/MANIFEST.MF b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..95c088a2cd
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/META-INF/MANIFEST.MF
@@ -0,0 +1,35 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: cipm.consistency.fluentapi.java;singleton:=true
+Bundle-Version: 0.2.0.qualifier
+Bundle-ClassPath: .
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Export-Package: cipm.consistency.fluentapi.java.api,
+ cipm.consistency.fluentapi.java.api.impl,
+ cipm.consistency.fluentapi.java.api.inits,
+ cipm.consistency.fluentapi.java.api.inits.impl,
+ cipm.consistency.fluentapi.java.api.inits.util,
+ cipm.consistency.fluentapi.java.api.placeholderTypes,
+ cipm.consistency.fluentapi.java.api.placeholderTypes.impl,
+ cipm.consistency.fluentapi.java.api.util,
+ cipm.consistency.fluentapi.java.builder,
+ cipm.consistency.fluentapi.java.metamodel,
+ cipm.consistency.fluentapi.java.postprocessor,
+ cipm.consistency.fluentapi.java.test,
+ cipm.consistency.fluentapi.java.test.metamodel
+Automatic-Module-Name: cipm.consistency.fluentapi.java
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Require-Bundle: cipm.consistency.fluentapi,
+ junit-jupiter-api,
+ junit-jupiter-engine,
+ junit-jupiter-params,
+ org.apache.log4j,
+ org.eclipse.emf.codegen.ecore,
+ org.eclipse.core.runtime,
+ org.eclipse.emf.ecore;visibility:=reexport,
+ org.eclipse.emf.ecore.xmi;visibility:=reexport,
+ org.emftext.language.java;visibility:=reexport,
+ org.apache.commons.lang
+Bundle-ActivationPolicy: lazy
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/README.md b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/README.md
new file mode 100644
index 0000000000..ec97eac9c9
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/README.md
@@ -0,0 +1,9 @@
+# Fluent API for Java
+
+This plug-in contains the implementation of the fluent API generation for Java and considers the (EMF-based) [JaMoPP metamodel for Java](https://github.com/MDSD-Tools/TheExtendedJavaModelParserAndPrinter). The structure of this plug-in reflects the structure of the [base plug-in for fluent API generation](../cipm.consistency.fluentapi/README.md).
+
+The fluent API class within this plug-in is called [FluentJavaAPI](./src-gen/cipm.consistency.fluentapi.java.api/FluentJavaAPI.java). Note that this class is not present in this plug-in by default will be generated from the fluent API model.
+
+Note that the Layout package and the relevant JaMoPP features are excluded in this implementation, in order to keep the generated fluent API code to the metamodel elements that are directly related to Java.
+
+For exemplary usage, refer to the test cases within the [test package of this plug-in](./src/cipm.consistency.fluentapi.java.test). For further details, refer to the [base plug-in for fluent API generation](../cipm.consistency.fluentapi/README.md).
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/build.properties b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/build.properties
new file mode 100644
index 0000000000..29969d1711
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/build.properties
@@ -0,0 +1,11 @@
+#
+
+bin.includes = .,\
+ metamodel/,\
+ META-INF/,\
+ plugin.xml,\
+ plugin.properties
+jars.compile.order = .
+source.. = src-gen/,\
+ src/
+output.. = bin/
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/plugin.properties b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/plugin.properties
new file mode 100644
index 0000000000..2f40076a23
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/plugin.properties
@@ -0,0 +1,4 @@
+#
+
+pluginName = java-fluentapi Model
+providerName = MCSE, KIT
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/plugin.xml b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/plugin.xml
new file mode 100644
index 0000000000..0304644be4
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/plugin.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/builder/FluentJavaAPIBuilder.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/builder/FluentJavaAPIBuilder.java
new file mode 100644
index 0000000000..e8071c6b44
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/builder/FluentJavaAPIBuilder.java
@@ -0,0 +1,92 @@
+package cipm.consistency.fluentapi.java.builder;
+
+import java.util.ArrayList;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelFactory;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import cipm.consistency.fluentapi.builder.FluentAPIAbstractBuilder;
+import cipm.consistency.fluentapi.gen.FluentAPIGenerationContext;
+import cipm.consistency.fluentapi.gen.FluentAPIGenerator;
+import cipm.consistency.fluentapi.java.metamodel.FluentAPIJavaMetamodelFilter;
+import cipm.consistency.fluentapi.java.metamodel.FluentAPIJavaMetamodelPackageProvider;
+import cipm.consistency.fluentapi.java.postprocessor.FluentAPIGenerationJavaMetamodelPostProcessor;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationBigNumberParameterPostProcessor;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationForEachOverloadPostProcessor;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationMultipleValueParameterSameMethodBodyOverloadPostProcessor;
+
+/**
+ * An implementation of {@link FluentAPIAbstractBuilder} for the JaMoPP
+ * metamodel.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentJavaAPIBuilder extends FluentAPIAbstractBuilder {
+ private static final FluentAPITargetMetamodelPackageProvider provider = new FluentAPIJavaMetamodelPackageProvider();
+ private static final FluentAPITargetMetamodelFilter filter = new FluentAPIJavaMetamodelFilter();
+
+ @Override
+ protected GenModel generateGenModel(Resource genModelRes, Resource ecoreRes, FluentAPIGenerationContext context) {
+ var genModel = GenModelFactory.eINSTANCE.createGenModel();
+ genModelRes.getContents().add(genModel);
+
+ genModel.setModelDirectory("/" + getGeneratedFluentAPIModelDirectoryPath().toString());
+ genModel.setOperationReflection(true);
+ genModel.setImportOrganizing(true);
+ genModel.setComplianceLevel(getJDKVersion());
+ genModel.setModelName(getModelName());
+ genModel.setModelPluginID(getModelPluginID());
+ genModel.getForeignModel().add(ecoreRes.getURI().lastSegment());
+
+ var targetMetamodelGenModel = provider.getTargetMetamodelGenModels().get(0);
+ genModel.getUsedGenPackages().addAll(targetMetamodelGenModel.getGenPackages());
+
+ var initEPacs = new ArrayList();
+ var toGen = (EPackage) ecoreRes.getContents().get(0);
+
+ initEPacs.add(toGen);
+ genModel.initialize(initEPacs);
+
+ genModel.reconcile();
+
+ genModel.setCanGenerate(true);
+
+ var apiGenPac = genModel.findGenPackage(toGen);
+ apiGenPac.setBasePackage(context.getBasePackageName());
+
+ return genModel;
+ }
+
+ @Override
+ protected void generateEcoreModel(Resource ecoreRes, FluentAPIGenerationContext context) {
+ new FluentAPIGenerator().generateRootAPIPackages(context);
+ new FluentAPIGenerationJavaMetamodelPostProcessor(context.getAllInitEClss(), provider).apply();
+ new FluentAPIGenerationBigNumberParameterPostProcessor(context.getAllInitEClss()).apply();
+
+ var allEClss = new ArrayList();
+ allEClss.add(context.getFluentAPIECls());
+ allEClss.add(context.getInitSuperECls());
+ allEClss.addAll(context.getAllInitEClss());
+
+ new FluentAPIGenerationForEachOverloadPostProcessor(context, allEClss).apply();
+ new FluentAPIGenerationMultipleValueParameterSameMethodBodyOverloadPostProcessor(context, allEClss).apply();
+
+ ecoreRes.getContents().add(context.getRootPackage());
+ }
+
+ @Override
+ protected FluentAPITargetMetamodelPackageProvider getTargetMetamodelPackageProvider() {
+ return provider;
+ }
+
+ @Override
+ protected FluentAPITargetMetamodelFilter getTargetMetamodelFilter() {
+ return filter;
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/builder/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/builder/package-info.java
new file mode 100644
index 0000000000..63b5b2f1e4
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/builder/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains the builder class, which is responsible for building the fluent api
+ * model (for JaMoPP) that consists of an ecore and a genmodel file.
+ */
+package cipm.consistency.fluentapi.java.builder;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/FluentAPIJavaMetamodelFilter.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/FluentAPIJavaMetamodelFilter.java
new file mode 100644
index 0000000000..8b6c89a3b6
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/FluentAPIJavaMetamodelFilter.java
@@ -0,0 +1,50 @@
+package cipm.consistency.fluentapi.java.metamodel;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.emftext.commons.layout.LayoutPackage;
+import org.emftext.language.java.commons.CommonsPackage;
+
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+
+/**
+ * An implementation of {@link FluentAPITargetMetamodelFilter} for
+ * JaMoPP.
+ *
+ *
+ * Excludes the features ( {@link EStructuralFeature} ) that are present in
+ * {@link Commentable} and its super-types. Also excludes EClasses found under
+ * {@link LayoutPackage}. All other EClasses and features under
+ * {@link JavaPackage} are included.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIJavaMetamodelFilter extends FluentAPITargetMetamodelFilter {
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * Excludes the features ( {@link EStructuralFeature} ) that are present in
+ * {@link Commentable} and its super-types. All other features under
+ * {@link JavaPackage} are included.
+ */
+ @Override
+ public boolean isFeatureEligible(EClass holderOfFeat, EStructuralFeature feat) {
+ return isFeatureChangeable(feat)
+ && !feat.getEContainingClass().getName().equals(CommonsPackage.Literals.COMMENTABLE.getName());
+// !CommonsPackage.Literals.COMMENTABLE.isSuperTypeOf(feat.getEContainingClass())
+// !feat.getEContainingClass().getInstanceClass().isAssignableFrom(Commentable.class)
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * Excludes EClasses found under the {@link LayoutPackage}. All other EClasses
+ * under {@link JavaPackage} are included.
+ */
+ @Override
+ public boolean isEClassEligible(EClass eCls) {
+ return eCls.getEPackage() == null || !eCls.getEPackage().getName().equals(LayoutPackage.eNAME);
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/FluentAPIJavaMetamodelPackageProvider.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/FluentAPIJavaMetamodelPackageProvider.java
new file mode 100644
index 0000000000..94ea6a9ab9
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/FluentAPIJavaMetamodelPackageProvider.java
@@ -0,0 +1,157 @@
+package cipm.consistency.fluentapi.java.metamodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+//import org.apache.commons.lang.StringUtils;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.emftext.commons.layout.LayoutPackage;
+import org.emftext.language.java.JavaPackage;
+
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.metamodel.MetamodelUtil;
+
+/**
+ * An implementation of {@link FluentAPITargetMetamodelPackageProvider} for
+ * JaMoPP.
+ *
+ *
+ * This class internally "fixes" the Ecore and GenModel of JaMoPP that it
+ * parses, in order to avoid having duplicated Resource instances during fluent
+ * api generation. This is due to Eclipse plug-in limitations.
+ *
+ *
+ * Note: The original JaMoPP metamodel considers both {@link JavaPackage} and
+ * {@link LayoutPackage}. In order to keep the parsed metamodels valid, this
+ * class parses both of them. For filtering out {@link LayoutPackage},
+ * {@link FluentAPIJavaMetamodelFilter} can be used.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIJavaMetamodelPackageProvider extends FluentAPITargetMetamodelPackageProvider {
+ /**
+ * The (plug-in based) URI to JaMoPP's genmodel file
+ */
+ private static final URI jaMoPPGenModelURI = URI
+ .createURI("platform:/plugin/org.emftext.language.java/metamodel/java.genmodel");
+ /**
+ * The (plug-in based) URI to JaMoPP's ecore file
+ */
+ private static final URI jaMoPPEcoreModelURI = URI
+ .createURI("platform:/plugin/org.emftext.language.java/metamodel/java.ecore");
+
+ /**
+ * The ResourceSet, which will contain the Resources of the GenModel and the
+ * Ecore model parsed by this class ( {@link #ecoreRes} and {@link #genModelRes}
+ * ). Note that those Resources are not the original Resources of the JaMoPP
+ * model.
+ */
+ private final ResourceSet metamodelResSet = new ResourceSetImpl();
+ /**
+ * The Resource instance containing the parsed Ecore model of JaMoPP. This is
+ * NOT the Resource instance of {@code JavaPackage.eINSTANCE} nor
+ * {@code LayoutPackage.eINSTANCE}.
+ */
+ private Resource ecoreRes;
+ /**
+ * The Resource instance containing the parsed GenModel of JaMoPP. This does NOT
+ * use the Resource instance of {@code JavaPackage.eINSTANCE} nor
+ * {@code LayoutPackage.eINSTANCE}, but {@link #ecoreRes}.
+ */
+ private Resource genModelRes;
+ /**
+ * The list containing the original JaMoPP EClasses that are available under
+ * {@code JavaPackage.eINSTANCE} and {@code LayoutPackage.eINSTANCE}. These
+ * EClasses are NOT the same as those in {@link #ecoreRes}.
+ */
+ private List originalEClss;
+
+ @Override
+ public String getTargetMetamodelName() {
+ var topPac = getTargetMetamodelEcoreEPackages().get(0);
+ return topPac.getName();
+ }
+
+ @Override
+ public List getAllTargetMetamodelEClasses() {
+ var topPac = getTargetMetamodelEcoreEPackages().get(0);
+ return List.copyOf(MetamodelUtil.getAllEClasses(topPac));
+ }
+
+ /**
+ * Caches the (original) EClasses found under the JaMoPP metamodel ( under
+ * {@code JavaPackage.eINSTANCE} and {@code LayoutPackage.eINSTANCE}) in
+ * {@link #originalEClss}, in order to spare constantly retrieving them from the
+ * Resource instances.
+ */
+ private void cacheOriginalEClasses() {
+ if (originalEClss == null) {
+ originalEClss = new ArrayList(MetamodelUtil.getAllEClasses(JavaPackage.eINSTANCE));
+ originalEClss.addAll(MetamodelUtil.getAllEClasses(LayoutPackage.eINSTANCE));
+ }
+ }
+
+ /**
+ * Changes the instance classes within the EClasses under parsedJaMoPPEcoreModel
+ * to the original EClasses from JaMoPP ( {@link #originalEClss} ).
+ *
+ * @param parsedJaMoPPEcoreModel The Ecore model of JaMoPP, which has been
+ * parsed by this class.
+ */
+ private void fixInstanceClasses(EPackage parsedJaMoPPEcoreModel) {
+ var jaMoPPParsedEClss = MetamodelUtil.getAllEClasses(parsedJaMoPPEcoreModel);
+ cacheOriginalEClasses();
+
+ if (jaMoPPParsedEClss.size() != originalEClss.size())
+ throw new IllegalStateException(
+ "Parsed Java package and the actual Java package contain different amounts of EClasses");
+
+ for (var parsedECls : jaMoPPParsedEClss) {
+ var matchingActualECls = originalEClss.stream()
+ .filter((cls) -> cls.getEPackage().getName().equals(parsedECls.getEPackage().getName()))
+ .filter((cls) -> cls.getName().equals(parsedECls.getName())).toArray(EClass[]::new);
+ if (matchingActualECls.length != 1)
+ throw new IllegalStateException("Unknown EClass has been parsed");
+
+ var actualECls = matchingActualECls[0];
+ parsedECls.setInstanceClassName(actualECls.getInstanceClassName());
+ parsedECls.setInstanceTypeName(actualECls.getInstanceTypeName());
+ parsedECls.setInstanceClass(actualECls.getInstanceClass());
+ }
+ }
+
+ @Override
+ public List getTargetMetamodelEcoreEPackages() {
+ if (ecoreRes == null) {
+ ecoreRes = metamodelResSet.getResource(jaMoPPEcoreModelURI, true);
+ var parsedJaMoPPEcoreModel = (EPackage) ecoreRes.getContents().get(0);
+ fixInstanceClasses(parsedJaMoPPEcoreModel);
+ }
+
+ return List.of((EPackage) ecoreRes.getContents().get(0));
+ }
+
+ @Override
+ public List getTargetMetamodelGenModels() {
+ if (genModelRes == null) {
+ genModelRes = metamodelResSet.getResource(jaMoPPGenModelURI, true);
+ }
+
+ var javaGenModel = (GenModel) genModelRes.getContents().get(0);
+ javaGenModel.setCanGenerate(false);
+
+ return List.of(javaGenModel);
+ }
+
+ @Override
+ public List getAllEClassesInOriginalMetamodel() {
+ cacheOriginalEClasses();
+ return originalEClss;
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/package-info.java
new file mode 100644
index 0000000000..f3c6b02272
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/metamodel/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains classes that provide access to the JaMoPP metamodel during the
+ * fluent api generation.
+ */
+package cipm.consistency.fluentapi.java.metamodel;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/postprocessor/FluentAPIGenerationJavaMetamodelPostProcessor.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/postprocessor/FluentAPIGenerationJavaMetamodelPostProcessor.java
new file mode 100644
index 0000000000..c1c5b88428
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/postprocessor/FluentAPIGenerationJavaMetamodelPostProcessor.java
@@ -0,0 +1,117 @@
+package cipm.consistency.fluentapi.java.postprocessor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.emftext.language.java.classifiers.ClassifiersPackage;
+import org.emftext.language.java.types.ClassifierReference;
+import org.emftext.language.java.types.TypesPackage;
+
+import cipm.consistency.fluentapi.gen.FluentAPIGenerationUtil;
+import cipm.consistency.fluentapi.gen.FluentAPIMethodsUtil;
+import cipm.consistency.fluentapi.gen.ModelConstants;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationPostProcessor;
+
+/**
+ * A post-processor that adds overloads for methods that use parameters of type
+ * {@link TypeReference} for convenience. Using the overloading methods spare
+ * having to manually construct {@link ClassifierReference}s for
+ * {@link Classifier}s, in order to create a TypeReference instance for them.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIGenerationJavaMetamodelPostProcessor implements FluentAPIGenerationPostProcessor {
+ private static final Pattern methodNamePatternToOverload = Pattern
+ .compile(String.join("|", ModelConstants.Initialiation.With.NAME.getFor(".*"),
+ ModelConstants.Initialiation.WithAdded.NAME.getFor(".*")));
+
+ private static final String typeReferenceParameterOverrideTemplate = ModelConstants.SuperInitialisation.ToAPI.NAME
+ .thisCall()
+ + ModelConstants.FluentAPI.New.NAME.callFor(new String[] { ClassifierReference.class.getSimpleName() })
+ + ModelConstants.Initialiation.With.NAME.callFor(new String[] { "Target" }, "%s")
+ + ModelConstants.SuperInitialisation.CreateNow.NAME.call();
+ private static final String typeReferenceParameterOverrideParameterDocumentation = "The classifier instance, which will be referenced";
+
+ /**
+ * {@link #getInitEClss()}
+ */
+ private List initEClss;
+ private FluentAPITargetMetamodelPackageProvider provider;
+
+ /**
+ * @param initEClss {@link #getInitEClss()}
+ */
+ public FluentAPIGenerationJavaMetamodelPostProcessor(List initEClss,
+ FluentAPITargetMetamodelPackageProvider provider) {
+ this.initEClss = initEClss;
+ this.provider = provider;
+ }
+
+ /**
+ * @return The list of {@link EClass}es that this post-processor should apply to
+ */
+ public List getInitEClss() {
+ return this.initEClss;
+ }
+
+ /**
+ * @return The object that grants access to the JaMoPP metamodel.
+ */
+ public FluentAPITargetMetamodelPackageProvider getTargetMetamodelPackageProvider() {
+ return provider;
+ }
+
+ private List createOverloadingMethodsFor(EOperation opToOverload) {
+ var copier = new EcoreUtil.Copier();
+ var overloadingOp = (EOperation) copier.copy(opToOverload);
+ copier.copyReferences();
+
+ // Adjust parameters
+
+ var paramExprs = new ArrayList();
+
+ for (int i = 0; i < overloadingOp.getEParameters().size(); i++) {
+ var currentParam = overloadingOp.getEParameters().get(i);
+ if (currentParam.getEType().equals(provider.getEClass(TypesPackage.Literals.TYPE_REFERENCE.getName()))) {
+ paramExprs.add(String.format(typeReferenceParameterOverrideTemplate, currentParam.getName()));
+ currentParam.setEType(provider.getEClass(ClassifiersPackage.Literals.CLASSIFIER.getName()));
+
+ // Add parameter documentation to clarify intent
+ FluentAPIGenerationUtil.addDocumentation(currentParam,
+ typeReferenceParameterOverrideParameterDocumentation);
+ } else {
+ paramExprs.add(currentParam.getName());
+ }
+ }
+
+ // Adjust method body
+ var serialisedParameters = String.join(",", paramExprs.toArray(String[]::new));
+ FluentAPIGenerationUtil.addBody(overloadingOp, FluentAPIMethodsUtil
+ .joinLOC("return this." + overloadingOp.getName() + "(" + serialisedParameters + ")"));
+
+ return List.of(overloadingOp);
+ }
+
+ @Override
+ public void apply() {
+ for (var initECls : this.getInitEClss()) {
+ var opsToOverload = initECls.getEOperations().stream()
+ .filter((op) -> methodNamePatternToOverload.matcher(op.getName()).matches())
+ .collect(Collectors.toList());
+ for (var op : opsToOverload) {
+ // Skip parameters of type EList, since overloading them results in type erasure
+ // related issues
+ if (op.getEParameters().stream().anyMatch((p) -> p.getEType() != null && !p.isMany()
+ && p.getEType().equals(provider.getEClass(TypesPackage.Literals.TYPE_REFERENCE.getName())))) {
+ initECls.getEOperations().addAll(createOverloadingMethodsFor(op));
+ }
+ }
+ }
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/postprocessor/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/postprocessor/package-info.java
new file mode 100644
index 0000000000..f1450ad05d
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/postprocessor/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains post-processors that can be used on the generated fluent api model
+ * for JaMoPP after its generation.
+ */
+package cipm.consistency.fluentapi.java.postprocessor;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIContainmentTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIContainmentTest.java
new file mode 100644
index 0000000000..a75d693a3b
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIContainmentTest.java
@@ -0,0 +1,109 @@
+package cipm.consistency.fluentapi.java.test;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * Tests the construction of models, where model elements of the same type are
+ * nested within one another. Also tests construction of model elements with
+ * multiple EReferences using values of the same type.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIContainmentTest extends AbstractFluentAPITest {
+ /**
+ * Tests whether model elements of the same type can be successfully nested in
+ * one another.
+ *
+ *
+ * Ensures that the following construction is possible and works as intended:
+ *
+ * class outer { class inner {} }
+ */
+ @Test
+ public void testNesting() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var innerClsName = "inner";
+ var outerClsName = "outer";
+
+ var innerCls = api.newClass().withName(innerClsName).createNow();
+ var outerCls = api.newClass().withName(outerClsName).withAddedMembers(innerCls).createNow();
+
+ Assertions.assertEquals(1, outerCls.getMembers().size());
+ Assertions.assertEquals(innerCls, outerCls.getMembers().get(0));
+ Assertions.assertEquals(0, outerCls.getDefaultMembers().size());
+ Assertions.assertNull(outerCls.eContainer());
+
+ Assertions.assertEquals(0, innerCls.getMembers().size());
+ Assertions.assertEquals(0, innerCls.getDefaultMembers().size());
+ Assertions.assertEquals(outerCls, innerCls.eContainer());
+ }
+
+ /**
+ * Tests whether it is possible to set the features of model elements to other
+ * (nested) model elements of the same type.
+ *
+ *
+ * Ensures that the following construction is possible and works as intended:
+ *
+ * class cls1 { class cls2 extends cls1 {} }
+ */
+ @Test
+ public void testNestingAndReferencing() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var outerClsName = "outer";
+ var innerClsName = "inner";
+
+ var outerCls = api.newClass().withName(outerClsName).createNow();
+ var innerCls = api.newClass().withName(innerClsName)
+ .withExtends(api.newClassifierReference().withTarget(outerCls).createNow()).createNow();
+ api.modifyClass(outerCls).withAddedMembers(innerCls).dropInitialisation();
+
+ Assertions.assertEquals(1, outerCls.getMembers().size());
+ Assertions.assertEquals(innerCls, outerCls.getMembers().get(0));
+ Assertions.assertEquals(0, outerCls.getDefaultMembers().size());
+ Assertions.assertNull(outerCls.eContainer());
+
+ Assertions.assertEquals(0, innerCls.getMembers().size());
+ Assertions.assertEquals(0, innerCls.getDefaultMembers().size());
+ Assertions.assertEquals(outerCls, innerCls.getExtends().getPureClassifierReference().getTarget());
+ Assertions.assertEquals(outerCls, innerCls.eContainer());
+ }
+
+ /**
+ * Tests whether fluent api sets the value of the correct feature of the model
+ * element.
+ *
+ *
+ * Ensures setting values EReferences using the same value type works as
+ * intended, for instance:
+ *
+ *
+ * PrimitiveTypeReference has the EReferences ArrayDimensionsBefore (ADB) and
+ * ArrayDimensionsAfter (ADA), which consider ArrayDimension instances AD1 and
+ * AD2. Assuming AD1 and AD2 are separate ArrayDimension instances, setting ADB
+ * = AD1 and ADA = AD2 via Fluent API should not mix up ADB and ADA.
+ */
+ @Test
+ public void testTwoContainmentFeaturesWithSameType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var arrDimBefore = api.newArrayDimension().createNow();
+ var arrDimAfter = api.newArrayDimension().createNow();
+ var ptr = api.newPrimitiveTypeReference().withAddedArrayDimensionsBefore(arrDimBefore)
+ .withAddedArrayDimensionsAfter(arrDimAfter).createNow();
+
+ Assertions.assertEquals(1, ptr.getArrayDimensionsBefore().size());
+ Assertions.assertEquals(arrDimBefore, ptr.getArrayDimensionsBefore().get(0));
+ Assertions.assertEquals(ptr, arrDimBefore.eContainer());
+
+ Assertions.assertEquals(1, ptr.getArrayDimensionsAfter().size());
+ Assertions.assertEquals(arrDimAfter, ptr.getArrayDimensionsAfter().get(0));
+ Assertions.assertEquals(ptr, arrDimAfter.eContainer());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitBigNumberOverloadsTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitBigNumberOverloadsTest.java
new file mode 100644
index 0000000000..36d3f3c7b9
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitBigNumberOverloadsTest.java
@@ -0,0 +1,77 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.math.BigInteger;
+
+import org.emftext.language.java.literals.DecimalIntegerLiteral;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class for checking whether fluent api model has overloading methods
+ * for operations that consider {@link BigInteger} parameters and that they work
+ * as intended.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIInitBigNumberOverloadsTest extends AbstractFluentAPITest {
+ /**
+ * Ensures that overloading methods for BigInteger are generated
+ */
+ @Test
+ public void testInit_OverloadedBigIntegerMethodsTest_SingleValue() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ final var lit = new DecimalIntegerLiteral[3];
+
+ BigInteger bigIntVal = BigInteger.valueOf(1);
+
+ // Ensure that the original method for BigInteger is generated
+ Assertions.assertDoesNotThrow(
+ () -> lit[0] = api.newDecimalIntegerLiteral().withDecimalValue(bigIntVal).createNow());
+ // Ensure that the original method for BigInteger works as intended
+ Assertions.assertEquals(bigIntVal, lit[0].getDecimalValue());
+
+ int intVal = bigIntVal.intValue();
+ Assertions.assertEquals(1, intVal);
+ // Ensure that the overloading method is generated (with int parameter)
+ Assertions
+ .assertDoesNotThrow(() -> lit[1] = api.newDecimalIntegerLiteral().withDecimalValue(intVal).createNow());
+ // Ensure that the overloading method works as intended
+ Assertions.assertEquals(intVal, lit[1].getDecimalValue().intValue());
+
+ long longVal = bigIntVal.longValue();
+ Assertions.assertEquals(1, longVal);
+ // Ensure that the overloading method is generated (with long parameter)
+ Assertions.assertDoesNotThrow(
+ () -> lit[2] = api.newDecimalIntegerLiteral().withDecimalValue(longVal).createNow());
+ // Ensure that the overloading method works as intended
+ Assertions.assertEquals(longVal, lit[2].getDecimalValue().longValue());
+ }
+
+ /**
+ * Ensures that direct creation methods for types with only one modifiable
+ * features is possible via the generated API class
+ */
+ @Test
+ public void testInit_OverloadedBigIntegerMethodsTest_OnlyOneSingleValuedModifiableFeature() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ final var obj = new DecimalIntegerLiteral[2];
+
+ int intVal = 1;
+ // Ensure that the overloading method is generated (with int parameter)
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newDecimalIntegerLiteral(intVal));
+ // Ensure that the overloading method works as intended
+ Assertions.assertInstanceOf(DecimalIntegerLiteral.class, obj[0]);
+ Assertions.assertEquals(intVal, obj[0].getDecimalValue().intValue());
+
+ long longVal = 1;
+ // Ensure that the overloading method is generated (with long parameter)
+ Assertions.assertDoesNotThrow(() -> obj[1] = api.newDecimalIntegerLiteral(longVal));
+ // Ensure that the overloading method works as intended
+ Assertions.assertInstanceOf(DecimalIntegerLiteral.class, obj[1]);
+ Assertions.assertEquals(longVal, obj[1].getDecimalValue().longValue());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitJavaOverloadsTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitJavaOverloadsTest.java
new file mode 100644
index 0000000000..9a18b1bef2
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitJavaOverloadsTest.java
@@ -0,0 +1,55 @@
+package cipm.consistency.fluentapi.java.test;
+
+import org.emftext.language.java.classifiers.Classifier;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class for checking whether certain methods in initialisations within
+ * the fluent api class for Java are overloaded as expected and that the
+ * overloaded versions work as intended.
+ *
+ *
+ * Currently only methods that consider {@link TypeReference} as parameter.
+ *
+ * @author Alp Torac Genc
+ * @see {@link FluentAPIGenerationJavaMetamodelPostProcessor} for more details
+ * on overloaded methods
+ */
+public class FluentAPIInitJavaOverloadsTest extends AbstractFluentAPITest {
+ /**
+ * Checks whether initialisation methods in fluent api for Java have an
+ * overloading variant that takes (a singular) Classifier parameters instead of
+ * TypeReferences and converts them into ClassifierTypeReferences.
+ */
+ @Test
+ public void testInit_WithTypeReferenceOverloadTest_SingleValued() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var cls = api.createNewClass();
+
+ var clsMet = api.newClassMethod().withTypeReference(cls).createNow();
+ Assertions.assertSame(cls, clsMet.getTypeReference().getPureClassifierReference().getTarget());
+ }
+
+ /**
+ * Checks whether initialisation methods in fluent api for Java have an
+ * overloading variant that takes multiple Classifier parameters instead of
+ * TypeReferences and converts them into ClassifierTypeReferences.
+ */
+ @Test
+ public void testInit_WithTypeReferenceOverloadTest_ManyValued() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsOne = api.createNewClass();
+ var clsTwo = api.createNewClass();
+
+ var ai = api.newAnnotationInstance().withAddedActualTargets(new Classifier[] { clsOne, clsTwo }).createNow();
+
+ Assertions.assertSame(clsOne, ai.getActualTargets().get(0).getPureClassifierReference().getTarget());
+ Assertions.assertSame(clsTwo, ai.getActualTargets().get(1).getPureClassifierReference().getTarget());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitTest.java
new file mode 100644
index 0000000000..4d32a79638
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitTest.java
@@ -0,0 +1,272 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.util.List;
+
+import org.emftext.language.java.classifiers.ClassifiersPackage;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.extensions.FluentAPIInitialisationStorage;
+import cipm.consistency.fluentapi.extensions.FluentAPIMarkExtension;
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class containing tests for initialisation classes within the fluent
+ * api model.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIInitTest extends AbstractFluentAPITest {
+ /**
+ * Checks whether init.getInitialisedEClass() works as intended.
+ */
+ @Test
+ public void testInit_getInitialisedEClass() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var eCls = ClassifiersPackage.Literals.CLASS;
+ Assertions.assertEquals(eCls, api.newX(eCls).getInitialisedEClass());
+ }
+
+ /**
+ * Checks whether init.toAPI() works as intended.
+ */
+ @Test
+ public void testInit_ToAPI() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ Assertions.assertSame(api, api.newAdditionalField().toAPI());
+ }
+
+ /**
+ * Checks whether init.reset() works as intended.
+ */
+ @Test
+ public void testInit_Reset() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsInit = api.newClass();
+ Assertions.assertNotNull(clsInit.getCurrentElement());
+
+ clsInit.reset();
+ Assertions.assertNull(clsInit.getCurrentElement());
+
+ // Ensure that reset() does not remove the Initialisation instance from API
+ Assertions.assertNotNull(api.continueClass());
+ }
+
+ /**
+ * Checks whether init.createNow() works as intended.
+ */
+ @Test
+ public void testInit_CreateNow() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var mod = api.newModule().createNow();
+ Assertions.assertInstanceOf(org.emftext.language.java.containers.Module.class, mod);
+
+ // Ensure that createNow() removes the Initialisation instance from api
+ Assertions.assertNull(api.continueModule());
+ }
+
+ /**
+ * Checks whether init.createNow(class) works as intended, when class is the
+ * exact type of the created object.
+ */
+ @Test
+ public void testInit_CreateNow_WithTypeCast_ExactType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var mod = api.newModule().createNow(org.emftext.language.java.containers.Module.class);
+ Assertions.assertInstanceOf(org.emftext.language.java.containers.Module.class, mod);
+ }
+
+ /**
+ * Checks whether init.createNow(class) works as intended, where class is a
+ * super-type of the created object.
+ */
+ @Test
+ public void testInit_CreateNow_WithTypeCast_Upcasting() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsToCastTo = org.emftext.language.java.commons.NamedElement.class;
+ var mod = api.newModule().createNow(clsToCastTo);
+ Assertions.assertInstanceOf(org.emftext.language.java.containers.Module.class, mod);
+ Assertions.assertInstanceOf(clsToCastTo, mod);
+ }
+
+ /**
+ * Checks whether init.createNow(class) works as intended, where class is a
+ * sub-type of the created object.
+ */
+ @Test
+ public void testInit_CreateNow_WithTypeCast_Downcasting() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsToCastTo = org.emftext.language.java.containers.impl.ModuleImpl.class;
+ var mod = api.newModule().createNow(clsToCastTo);
+ Assertions.assertInstanceOf(org.emftext.language.java.containers.Module.class, mod);
+ Assertions.assertInstanceOf(clsToCastTo, mod);
+
+ // Make sure that the method basicGetOpen() in ModuleImpl is actually found
+ // during compilation (not present in
+ // org.emftext.language.java.containers.Module, which is the usual return type
+ // of api.newModule().createNow())
+ Assertions.assertDoesNotThrow(() -> mod.basicGetOpen());
+ }
+
+ /**
+ * Checks whether init.dropInitialisation() works as intended.
+ */
+ @Test
+ public void testInit_DropInitialisation() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsInit = api.newClass();
+
+ // Ensure that clsInit is added to FluentAPIInitialisationStorage
+ var inits = FluentAPIInitialisationStorage.getOngoingInitialisations();
+ Assertions.assertEquals(1, inits.size());
+ Assertions.assertSame(clsInit, inits.get(0));
+
+ clsInit.dropInitialisation();
+ // Re-retrieve ongoing initialisations
+ inits = FluentAPIInitialisationStorage.getOngoingInitialisations();
+ // Ensure that clsInit is removed from FluentAPIInitialisationStorage
+ Assertions.assertEquals(0, inits.size());
+ }
+
+ /**
+ * Checks whether init.markCurrentElement(key) works as intended.
+ */
+ @Test
+ public void testInit_MarkCurrentElement() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var key = new Object();
+
+ var clsInit = api.newClass();
+ var cls = clsInit.markCurrentElement(key).getCurrentElement();
+
+ Assertions.assertTrue(FluentAPIMarkExtension.hasMark(key));
+ Assertions.assertSame(cls, FluentAPIMarkExtension.getMarked(key));
+ }
+
+ /**
+ * Checks whether init.unmarkCurrentElement(key) works as intended.
+ */
+ @Test
+ public void testInit_UnmarkCurrentElement() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var key = new Object();
+
+ var clsInit = api.newClass();
+ var cls = clsInit.markCurrentElement(key).getCurrentElement();
+
+ Assertions.assertTrue(FluentAPIMarkExtension.hasMark(key));
+ Assertions.assertSame(cls, FluentAPIMarkExtension.getMarked(key));
+
+ clsInit.unmarkCurrentElement(key);
+
+ Assertions.assertFalse(FluentAPIMarkExtension.hasMark(key));
+ Assertions.assertNull(FluentAPIMarkExtension.getMarked(key));
+ }
+
+ /**
+ * Checks whether init.waitForMark(singleKey, task) works as intended.
+ */
+ @Test
+ public void testInit_WaitForMark_SingleKey() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsOneName = "clsOne";
+ var clsTwoName = "clsTwo";
+ var clsOneKey = new Object();
+ var clsTwoKey = new Object();
+
+ // Goal:
+ // class clsOne extends clsTwo {}
+ // class clsTwo {}
+
+ var clsOne =
+ // Create clsOne (in isolation)
+ api.newClass().withName(clsOneName).markCurrentElement(clsOneKey)
+ // Have clsOne extend clsTwo, once clsTwo exists and is marked with clsTwoKey
+ .waitForMark(clsTwoKey,
+ () -> api.continueMarkedClass(clsOneKey).withExtends(api.getMarkedClass(clsTwoKey)))
+ // Create clsTwo and mark it
+ .toAPI().newClass().withName(clsTwoName).markCurrentElement(clsTwoKey)
+ // Swap to clsOne and return it
+ .toAPI().continueMarkedClass(clsOneKey).createNow();
+
+ Assertions.assertEquals(clsOneName, clsOne.getName());
+ Assertions.assertEquals(clsTwoName, clsOne.getExtends().getPureClassifierReference().getTarget().getName());
+ }
+
+ /**
+ * Checks whether init.waitForMark(keyArray, task) works as intended.
+ */
+ @Test
+ public void testInit_WaitForMark_KeyArray() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsOneName = "clsOne";
+ var clsTwoName = "clsTwo";
+ var clsThreeName = "clsThree";
+ var clsOneKey = new Object();
+ var clsTwoKey = new Object();
+ var clsThreeKey = new Object();
+ var clsMemberKeys = new Object[] { clsTwoKey, clsThreeKey };
+
+ // Goal:
+ // class clsOne {class clsTwo {} class clsThree {}}
+
+ var clsOne =
+ // Create clsOne (in isolation)
+ api.newClass().withName(clsOneName).markCurrentElement(clsOneKey)
+ // Add clsTwo and clsThree to clsOne once both of them are present and marked
+ .waitForMark(clsMemberKeys,
+ () -> api.continueMarkedClass(clsOneKey).withAddedMembers(
+ List.of(api.getMarkedClass(clsTwoKey), api.getMarkedClass(clsThreeKey))))
+ // Create clsTwo and mark it
+ .toAPI().newClass().withName(clsTwoName).markCurrentElement(clsTwoKey)
+ // Create clsThree and mark it
+ .toAPI().newClass().withName(clsThreeName).markCurrentElement(clsThreeKey)
+ // Swap to clsOne and return it
+ .toAPI().continueMarkedClass(clsOneKey).createNow();
+
+ Assertions.assertEquals(clsOneName, clsOne.getName());
+ Assertions.assertEquals(2, clsOne.getMembers().size());
+ Assertions.assertEquals(clsTwoName, clsOne.getMembers().get(0).getName());
+ Assertions.assertEquals(clsThreeName, clsOne.getMembers().get(1).getName());
+ }
+
+ /**
+ * Checks whether init.waitForMark(keyCollection, task) works as intended.
+ */
+ @Test
+ public void testInit_WaitForMark_KeyCollection() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsOneName = "clsOne";
+ var clsTwoName = "clsTwo";
+ var clsThreeName = "clsThree";
+ var clsOneKey = new Object();
+ var clsTwoKey = new Object();
+ var clsThreeKey = new Object();
+ var clsMemberKeys = List.of(clsTwoKey, clsThreeKey);
+
+ // Goal:
+ // class clsOne {class clsTwo {} class clsThree {}}
+
+ var clsOne =
+ // Create clsOne (in isolation)
+ api.newClass().withName(clsOneName).markCurrentElement(clsOneKey)
+ // Add clsTwo and clsThree to clsOne once both of them are present and marked
+ .waitForMark(clsMemberKeys,
+ () -> api.continueMarkedClass(clsOneKey).withAddedMembers(
+ List.of(api.getMarkedClass(clsTwoKey), api.getMarkedClass(clsThreeKey))))
+ // Create clsTwo and mark it
+ .toAPI().newClass().withName(clsTwoName).markCurrentElement(clsTwoKey)
+ // Create clsThree and mark it
+ .toAPI().newClass().withName(clsThreeName).markCurrentElement(clsThreeKey)
+ // Swap to clsOne and return it
+ .toAPI().continueMarkedClass(clsOneKey).createNow();
+
+ Assertions.assertEquals(clsOneName, clsOne.getName());
+ Assertions.assertEquals(2, clsOne.getMembers().size());
+ Assertions.assertEquals(clsTwoName, clsOne.getMembers().get(0).getName());
+ Assertions.assertEquals(clsThreeName, clsOne.getMembers().get(1).getName());
+ }
+
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitWithTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitWithTest.java
new file mode 100644
index 0000000000..c783915edb
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIInitWithTest.java
@@ -0,0 +1,329 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+import cipm.consistency.fluentapi.test.FluentAPITestUtils;
+
+/**
+ * A test class containing tests for modification methods of the initialisation
+ * classes within the fluent api model.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIInitWithTest extends AbstractFluentAPITest {
+ /**
+ * Checks whether init.withX(...) works as intended.
+ */
+ @Test
+ public void testInit_With() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var name = "cuName";
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ Assertions.assertNull(cu.getName());
+
+ init.withName(name);
+ Assertions.assertEquals(name, cu.getName());
+ }
+
+ /**
+ * Checks whether init.withoutX(...) works as intended.
+ */
+ @Test
+ public void testInit_Without() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var name = "cuName";
+ var cu = api.createNewCompilationUnit();
+ cu.setName(name);
+ var init = api.modifyCompilationUnit(cu);
+ Assertions.assertEquals(name, cu.getName());
+
+ init.withoutName();
+ Assertions.assertNull(cu.getName());
+ }
+
+ /**
+ * Checks whether init.withRemovedX(val) works as intended, if val is not an
+ * eligible value.
+ */
+ @Test
+ public void testInit_WithRemoved_RemoveNonExistentValue() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withRemovedNamespaces("ns4");
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withRemovedX(val) works as intended.
+ */
+ @Test
+ public void testInit_WithRemoved_SingularParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+ var expectedNss = List.of(ns2, ns3);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withRemovedNamespaces(ns1);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withRemovedX(valArray) works as intended.
+ */
+ @Test
+ public void testInit_WithRemoved_ArrayParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+ var toRemove = new String[] { ns1, ns3 };
+ var expectedNss = List.of(ns2);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withRemovedNamespaces(toRemove);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withRemovedX(valArray) works as intended, if valArray
+ * were empty.
+ */
+ @Test
+ public void testInit_WithRemoved_EmptyArrayParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ init.withRemovedNamespaces(new String[] {});
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+
+ /**
+ * Checks whether init.withRemovedX(valCollection) works as intended.
+ */
+ @Test
+ public void testInit_WithRemoved_CollectionParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+ var toRemove = List.of(ns1, ns3);
+ var expectedNss = List.of(ns2);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withRemovedNamespaces(toRemove);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withRemovedX(valCollection) works as intended, if
+ * valCollection were empty.
+ */
+ @Test
+ public void testInit_WithRemoved_EmptyCollectionParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ init.withRemovedNamespaces(List.of());
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+
+ /**
+ * Checks whether init.clean() works as intended.
+ */
+ @Test
+ public void testInit_Clean() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.cleanNamespaces();
+ Assertions.assertEquals(0, cu.getNamespaces().size());
+ }
+
+ /**
+ * Checks whether init.withAddedX(val) works as intended, if there were no prior
+ * values.
+ */
+ @Test
+ public void testInit_WithAdded_SingularParameter_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var ns = "ns";
+
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+
+ init.withAddedNamespaces(ns);
+ Assertions.assertEquals(1, cu.getNamespaces().size());
+ Assertions.assertEquals(ns, cu.getNamespaces().get(0));
+ }
+
+ /**
+ * Checks whether init.withAddedX(val) works as intended, if there were prior
+ * values.
+ */
+ @Test
+ public void testInit_WithAdded_SingularParameter_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+ var nsToAdd = "ns";
+ var expectedNss = List.of("ns1", "ns2", nsToAdd);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(nss);
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withAddedNamespaces(nsToAdd);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withAddedX(valArray) works as intended, if there were no
+ * prior values.
+ */
+ @Test
+ public void testInit_WithAdded_ArrayParameter_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = new String[] { "ns1", "ns2" };
+
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+
+ init.withAddedNamespaces(nss);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withAddedX(valArray) works as intended, if there were
+ * prior values.
+ */
+ @Test
+ public void testInit_WithAdded_ArrayParameter_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+ var nssToAdd = new String[] { "ns3", "ns4" };
+ var expectedNss = List.of("ns1", "ns2", "ns3", "ns4");
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(nss);
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withAddedNamespaces(nssToAdd);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withAddedX(valArray) works as intended, if valArray were
+ * empty.
+ */
+ @Test
+ public void testInit_WithAdded_EmptyArrayParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ init.withAddedNamespaces(new String[] {});
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+
+ /**
+ * Checks whether init.withAddedX(valCollection) works as intended, if there
+ * were no prior values.
+ */
+ @Test
+ public void testInit_WithAdded_CollectionParameter_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+
+ init.withAddedNamespaces(nss);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withAddedX(valCollection) works as intended, if there
+ * were prior values.
+ */
+ @Test
+ public void testInit_WithAdded_CollectionParameter_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+ var nssToAdd = List.of("ns3", "ns4");
+ var expectedNss = List.of("ns1", "ns2", "ns3", "ns4");
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(nss);
+ var init = api.modifyCompilationUnit(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.withAddedNamespaces(nssToAdd);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether init.withAddedX(valCollection) works as intended, if
+ * valCollection were empty.
+ */
+ @Test
+ public void testInit_WithAdded_EmptyCollectionParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyCompilationUnit(cu);
+ init.withAddedNamespaces(List.of());
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIContinueTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIContinueTest.java
new file mode 100644
index 0000000000..9dae4e96a5
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIContinueTest.java
@@ -0,0 +1,132 @@
+package cipm.consistency.fluentapi.java.test;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class for the following fluent api class methods: continue...(),
+ * continueX(), continueMarked...(), continueMarkedX().
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPIContinueTest extends AbstractFluentAPITest {
+ /**
+ * Checks whether the api.continueX() method works as intended.
+ */
+ @Test
+ public void testAPI_Continue_TopLevel() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var modInit = api.newModule();
+ var pacInit = api.newPackage();
+
+ var continuedModInit = api.continueX(org.emftext.language.java.containers.Module.class);
+ Assertions.assertSame(modInit, continuedModInit);
+ var continuedPacInit = api.continueX(org.emftext.language.java.containers.Package.class);
+ Assertions.assertSame(pacInit, continuedPacInit);
+ }
+
+ /**
+ * Checks whether the api.continueX() method works as intended, when the
+ * construction of the same element is continued.
+ */
+ @Test
+ public void testAPI_Continue_SameElementInstance() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var modInit = api.newModule();
+ var continuedModInit = api.continueModule();
+
+ Assertions.assertSame(modInit, continuedModInit);
+ }
+
+ /**
+ * Checks whether the api.continueX() method works as intended, when the
+ * construction of a different element of the same type is continued.
+ */
+ @Test
+ public void testAPI_Continue_SameElementType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var modInit1 = api.newModule();
+ var modInit2 = api.newModule();
+ Assertions.assertNotSame(modInit1, modInit2);
+ Assertions.assertSame(modInit2, api.continueModule());
+ }
+
+ /**
+ * Checks whether the api.continueX() method works as intended, when the
+ * construction of a different element is continued.
+ */
+ @Test
+ public void testAPI_Continue_DifferentElementType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var modInit = api.newModule();
+ var pacInit = api.newPackage();
+
+ Assertions.assertSame(modInit, api.continueModule());
+ Assertions.assertSame(pacInit, api.continuePackage());
+ }
+
+ /**
+ * Checks whether api.continueX() returns null, if there is no XInitialisation
+ * instance to be found
+ */
+ @Test
+ public void testAPI_Continue_NoInitialisation() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ Assertions.assertNull(api.continueModule());
+ }
+
+ /**
+ * Checks whether the api.continueMarked...() method works as intended, when
+ * there is only one Initialisation instance.
+ */
+ @Test
+ public void testAPI_ContinueMarked_SingleInitialisation() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var modKey = new Object();
+
+ var modInit = api.newModule().markCurrentElement(modKey);
+
+ Assertions.assertSame(modInit, api.continueMarkedModule(modKey));
+ }
+
+ /**
+ * Checks whether the api.continueMarked...() method works as intended, when
+ * there are multiple Initialisation instances.
+ */
+ @Test
+ public void testAPI_ContinueMarked_MultipleInitialisation() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var keyOne = new Object();
+ var keyTwo = new Object();
+
+ var modInitOne = api.newModule().markCurrentElement(keyOne);
+ var modInitTwo = api.newModule().markCurrentElement(keyTwo);
+
+ Assertions.assertSame(modInitOne, api.continueMarkedModule(keyOne));
+ Assertions.assertSame(modInitTwo, api.continueMarkedModule(keyTwo));
+ }
+
+ /**
+ * Checks whether the api.continueMarkedX() method works as intended.
+ */
+ @Test
+ public void testAPI_ContinueMarked_TopLevel() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var keyOne = new Object();
+ var keyTwo = new Object();
+
+ var modInit = api.newModule().markCurrentElement(keyOne);
+ var pacInit = api.newPackage().markCurrentElement(keyTwo);
+
+ Assertions.assertSame(modInit, api.continueMarkedX(keyOne));
+ Assertions.assertSame(pacInit, api.continueMarkedX(keyTwo));
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIGetOngoingInitTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIGetOngoingInitTest.java
new file mode 100644
index 0000000000..cbc3cba6c1
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIGetOngoingInitTest.java
@@ -0,0 +1,74 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class for the following fluent api class methods: getOngoingInits(),
+ * clearAllOngoingInits().
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPIGetOngoingInitTest extends AbstractFluentAPITest {
+ /**
+ * Checks whether api.getOngoingInitialisations() returns an empty list, if
+ * there are no initialisations.
+ */
+ @Test
+ public void testAPI_GetOngoingInitialisations_NoInitialisations() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ Assertions.assertEquals(0, api.getOngoingInitialisations().size());
+ }
+
+ /**
+ * Checks whether api.getOngoingInitialisations() works as intended.
+ */
+ @Test
+ public void testAPI_GetOngoingInitialisations() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsInit = api.newClass();
+
+ Assertions.assertEquals(1, api.getOngoingInitialisations().size());
+ Assertions.assertSame(clsInit, api.getOngoingInitialisations().get(0));
+ }
+
+ /**
+ * Ensures that different fluent api instances share the same initialisation
+ * instances.
+ */
+ @Test
+ public void testAPI_GetOngoingInitialisations_DifferentAPIInstances() {
+ var apiOne = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var apiTwo = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var init1 = apiOne.newClass();
+ var init2 = apiTwo.newClass();
+ var init3 = apiOne.newClass();
+
+ for (var api : List.of(apiOne, apiTwo)) {
+ Assertions.assertEquals(3, api.getOngoingInitialisations().size());
+ Assertions.assertSame(init1, api.getOngoingInitialisations().get(0));
+ Assertions.assertSame(init2, api.getOngoingInitialisations().get(1));
+ Assertions.assertSame(init3, api.getOngoingInitialisations().get(2));
+ }
+ }
+
+ /**
+ * Ensures that api.clearAllOngoingInitialisations() works as intended.
+ */
+ @Test
+ public void testAPI_ClearAllOngoingInitialisations() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ api.newClass();
+ api.newInterface();
+ Assertions.assertEquals(2, api.getOngoingInitialisations().size());
+ api.clearAllOngoingInitialisations();
+ Assertions.assertEquals(0, api.getOngoingInitialisations().size());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPINewMethodTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPINewMethodTest.java
new file mode 100644
index 0000000000..f4d263bf24
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPINewMethodTest.java
@@ -0,0 +1,166 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.emftext.language.java.containers.ContainersPackage;
+import org.emftext.language.java.expressions.AndExpression;
+import org.emftext.language.java.expressions.AndExpressionChild;
+import org.emftext.language.java.literals.DecimalIntegerLiteral;
+import org.emftext.language.java.modifiers.Abstract;
+import org.emftext.language.java.statements.Break;
+import org.emftext.language.java.variables.AdditionalLocalVariable;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.java.api.FluentAPISuperInitialisation;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class for the following methods of fluent api class: new...(), newX(),
+ * createNew...(), createNewX().
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPINewMethodTest extends AbstractFluentAPITest {
+ /**
+ * Ensures that direct creation methods for types with no modifiable features is
+ * possible via the generated API
+ */
+ @Test
+ public void testAPI_New_NoModifiableFeatures() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ final var obj = new Abstract[1];
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newAbstract());
+ Assertions.assertInstanceOf(Abstract.class, obj[0]);
+ }
+
+ /**
+ * Ensures that direct creation methods for types with only one modifiable
+ * features is possible via the generated API class
+ */
+ @Test
+ public void testAPI_New_OnlyOneSingleValuedModifiableFeature_EAttribute() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var val = BigInteger.valueOf(1);
+ final var obj = new DecimalIntegerLiteral[1];
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newDecimalIntegerLiteral(val));
+ Assertions.assertInstanceOf(DecimalIntegerLiteral.class, obj[0]);
+ Assertions.assertEquals(val, obj[0].getDecimalValue());
+ }
+
+ /**
+ * Ensures that direct creation methods for types with only one modifiable
+ * features is possible via the generated API class
+ */
+ @Test
+ public void testAPI_New_OnlyOneSingleValuedModifiableFeature_EReference() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var val = api.createNewJumpLabel();
+ final var obj = new Break[1];
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newBreak(val));
+ Assertions.assertInstanceOf(Break.class, obj[0]);
+ Assertions.assertSame(val, obj[0].getTarget());
+ }
+
+ /**
+ * Ensures that direct creation methods for types with only one modifiable
+ * features is possible via the generated API class
+ */
+ @Test
+ public void testAPI_New_OnlyOneManyValuedModifiableFeature_EReference_SingleValue() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var val = api.createNewEqualityExpression();
+ final var obj = new AndExpression[1];
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newAndExpression(val));
+ Assertions.assertInstanceOf(AndExpression.class, obj[0]);
+ Assertions.assertSame(val, obj[0].getChildren().get(0));
+ }
+
+ /**
+ * Ensures that direct creation methods for types with only one modifiable
+ * features is possible via the generated API class
+ */
+ @Test
+ public void testAPI_New_OnlyOneManyValuedModifiableFeature_EReference_Array() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var val = new AndExpressionChild[] { api.createNewEqualityExpression(), api.createNewEqualityExpression() };
+ final var obj = new AndExpression[1];
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newAndExpression(val));
+ Assertions.assertInstanceOf(AndExpression.class, obj[0]);
+ Assertions.assertSame(val[0], obj[0].getChildren().get(0));
+ Assertions.assertSame(val[1], obj[0].getChildren().get(1));
+ }
+
+ /**
+ * Ensures that direct creation methods for types with only one modifiable
+ * features is possible via the generated API class
+ */
+ @Test
+ public void testAPI_New_OnlyOneManyValuedModifiableFeature_EReference_Collection() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var val = List.of(api.createNewEqualityExpression(), api.createNewEqualityExpression());
+ final var obj = new AndExpression[1];
+ Assertions.assertDoesNotThrow(() -> obj[0] = api.newAndExpression(val));
+ Assertions.assertInstanceOf(AndExpression.class, obj[0]);
+ Assertions.assertSame(val.get(0), obj[0].getChildren().get(0));
+ Assertions.assertSame(val.get(1), obj[0].getChildren().get(1));
+ }
+
+ /**
+ * Ensures that instantiation of types with multiple modifiable features is
+ * possible via Initialisation classes.
+ */
+ @Test
+ public void testAPI_New_MultipleModifiableFeatures() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var init = api.newAdditionalLocalVariable();
+ Assertions.assertInstanceOf(FluentAPISuperInitialisation.class, init);
+ Assertions.assertInstanceOf(AdditionalLocalVariable.class, init.createNow());
+ }
+
+ /**
+ * Ensures that api.newX(EClass) works as intended.
+ */
+ @Test
+ public void testAPI_NewX_WithEClass() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ContainersPackage.Literals.MODULE.getInstanceClass();
+ var mod = api.newX(cls).createNow();
+ Assertions.assertInstanceOf(cls, mod);
+ }
+
+ /**
+ * Ensures that api.newX(class) works as intended.
+ */
+ @Test
+ public void testAPI_NewX_WithClass() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ContainersPackage.Literals.MODULE.getInstanceClass();
+ var mod = api.newX(cls).createNow();
+ Assertions.assertInstanceOf(cls, mod);
+ }
+
+ /**
+ * Ensures that api.createNewX(class) works as intended.
+ */
+ @Test
+ public void testAPI_CreateNewX() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ContainersPackage.Literals.MODULE.getInstanceClass();
+ var mod = api.createNewX(cls);
+ Assertions.assertInstanceOf(cls, mod);
+ }
+
+ /**
+ * Ensures that api.createNewX() works as intended, where X is the type of the
+ * model element to create.
+ */
+ @Test
+ public void testAPI_CreateNew() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var mod = api.createNewModule();
+ Assertions.assertInstanceOf(org.emftext.language.java.containers.Module.class, mod);
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPITest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPITest.java
new file mode 100644
index 0000000000..94ceaa4e29
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPITest.java
@@ -0,0 +1,276 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.emftext.language.java.classifiers.ClassifiersFactory;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.extensions.FluentAPIInitialisationStorage;
+import cipm.consistency.fluentapi.extensions.FluentAPIMarkExtension;
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.java.metamodel.FluentAPIJavaMetamodelFilter;
+import cipm.consistency.fluentapi.java.metamodel.FluentAPIJavaMetamodelPackageProvider;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+
+/**
+ * A test class for fluent api class.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPITest extends AbstractFluentAPITest {
+ /**
+ * Checks whether api.mark(key, obj) works as intended
+ */
+ @Test
+ public void testAPI_Mark() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ClassifiersFactory.eINSTANCE.createClass();
+ var clsKey = new Object();
+
+ api.mark(clsKey, cls);
+ Assertions.assertSame(cls, FluentAPIMarkExtension.getMarked(clsKey));
+ }
+
+ /**
+ * Ensures that different fluent api instances share the same marks.
+ */
+ @Test
+ public void testAPI_Mark_DifferentAPIs() {
+ var keyOne = new Object();
+ var apiOne = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsOne = ClassifiersFactory.eINSTANCE.createClass();
+
+ apiOne.mark(keyOne, clsOne);
+
+ var keyTwo = new Object();
+ var apiTwo = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var clsTwo = ClassifiersFactory.eINSTANCE.createClass();
+
+ apiTwo.mark(keyTwo, clsTwo);
+
+ Assertions.assertSame(clsOne, apiOne.getMarkedX(keyOne));
+ Assertions.assertSame(clsTwo, apiOne.getMarkedX(keyTwo));
+ Assertions.assertSame(clsOne, apiTwo.getMarkedX(keyOne));
+ Assertions.assertSame(clsTwo, apiTwo.getMarkedX(keyTwo));
+ }
+
+ /**
+ * Checks that api.unmark(key) works as intended.
+ */
+ @Test
+ public void testAPI_Unmark_WithKey() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ClassifiersFactory.eINSTANCE.createClass();
+ var clsKey = new Object();
+
+ api.mark(clsKey, cls);
+ Assertions.assertSame(cls, FluentAPIMarkExtension.getMarked(clsKey));
+ api.unmark(clsKey);
+ Assertions.assertNull(FluentAPIMarkExtension.getMarked(clsKey));
+ }
+
+ /**
+ * Checks that api.unmark(key, val) works as intended.
+ */
+ @Test
+ public void testAPI_Unmark_WithKeyAndValue() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ClassifiersFactory.eINSTANCE.createClass();
+ var clsKey = new Object();
+
+ api.mark(clsKey, cls);
+ Assertions.assertSame(cls, FluentAPIMarkExtension.getMarked(clsKey));
+ api.unmark(clsKey, cls);
+ Assertions.assertNull(FluentAPIMarkExtension.getMarked(clsKey));
+ }
+
+ /**
+ * Checks whether api.getMarkedX(key) works as intended
+ */
+ @Test
+ public void testAPI_GetMarkedX() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ClassifiersFactory.eINSTANCE.createClass();
+ var clsKey = new Object();
+
+ api.mark(clsKey, cls);
+ // Retrieve regardless of type
+ Assertions.assertSame(cls, api.getMarkedX(clsKey));
+ }
+
+ /**
+ * Checks whether api.getMarkedX(key) works as intended, where X is the exact
+ * type of the model element.
+ */
+ @Test
+ public void testAPI_GetMarkedType_MatchingType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ClassifiersFactory.eINSTANCE.createClass();
+ var clsKey = new Object();
+
+ api.mark(clsKey, cls);
+ Assertions.assertSame(cls, api.getMarkedClass(clsKey));
+ }
+
+ /**
+ * Checks whether api.getMarkedX(key) works as intended, where X is a super-type
+ * of the model element
+ */
+ @Test
+ public void testAPI_GetMarkedType_AbstractSuperType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cls = ClassifiersFactory.eINSTANCE.createClass();
+ var clsKey = new Object();
+
+ api.mark(clsKey, cls);
+ Assertions.assertSame(cls, api.getMarkedNamedElement(clsKey));
+ }
+
+ /**
+ * Checks whether api.modifyX(obj) works as intended.
+ */
+ @Test
+ public void testAPI_ModifyX() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var cls = api.newClass().createNow();
+
+ var init = api.modifyX(cls);
+ // Ensure that modifyX() does not remove the Initialisation instance
+ Assertions.assertEquals(1, FluentAPIInitialisationStorage.getOngoingInitialisations().size());
+ Assertions.assertSame(init, FluentAPIInitialisationStorage.getOngoingInitialisations().get(0));
+
+ var cls2 = init.createNow();
+ Assertions.assertSame(cls, cls2);
+ }
+
+ /**
+ * Checks whether api.modifyX(obj) works as intended, where X is the type of
+ * obj.
+ */
+ @Test
+ public void testAPI_ModifyType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var cls = api.newClass().createNow();
+
+ var init = api.modifyClass(cls);
+ // Ensure that modifyX() does not remove the Initialisation instance
+ Assertions.assertEquals(1, FluentAPIInitialisationStorage.getOngoingInitialisations().size());
+ Assertions.assertSame(init, FluentAPIInitialisationStorage.getOngoingInitialisations().get(0));
+
+ var cls2 = init.createNow();
+ Assertions.assertSame(cls, cls2);
+ }
+
+ /**
+ * Checks whether api.modifyMarkedX(obj) works as intended.
+ */
+ @Test
+ public void testAPI_ModifyMarkedX() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsKey = new Object();
+ var cls = api.newClass().markCurrentElement(clsKey).createNow();
+
+ Assertions.assertSame(cls, api.getMarkedClass(clsKey));
+
+ var cls2 = api.modifyMarkedX(clsKey).createNow();
+ Assertions.assertSame(cls, cls2);
+
+ }
+
+ /**
+ * Checks whether api.modifyMarkedX(obj) works as intended, where X is the type
+ * of obj.
+ */
+ @Test
+ public void testAPI_ModifyMarkedType() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsKey = new Object();
+ var cls = api.newClass().markCurrentElement(clsKey).createNow();
+
+ Assertions.assertSame(cls, api.getMarkedClass(clsKey));
+
+ var cls2 = api.modifyMarkedClass(clsKey).createNow();
+ Assertions.assertSame(cls, cls2);
+
+ }
+
+ /**
+ * Checks whether api.getAllSupportedClasses() works as intended.
+ */
+ @Test
+ public void testAPI_GetAllSupportedClasses() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var supportedClasses = api.getAllSupportedClasses();
+ var provider = new FluentAPIJavaMetamodelPackageProvider();
+ var filter = new FluentAPIJavaMetamodelFilter();
+ var expectedSupportedEClasses = provider.getAllTargetMetamodelConcreteEClasses().stream()
+ .filter((eCls) -> filter.isEClassEligible(eCls)).collect(Collectors.toList());
+ var expectedSupportedClasses = expectedSupportedEClasses.stream().map((eCls) -> eCls.getInstanceClass())
+ .collect(Collectors.toList());
+ Assertions.assertEquals(expectedSupportedClasses.size(), supportedClasses.size());
+ Assertions.assertTrue(supportedClasses.containsAll(expectedSupportedClasses));
+ var originalEClasses = provider.getAllConcreteEClassesInOriginalMetamodel().stream()
+ .filter((eCls) -> filter.isEClassEligible(eCls)).collect(Collectors.toList());
+ Assertions.assertEquals(originalEClasses.size(), supportedClasses.size());
+ Assertions.assertTrue(originalEClasses.stream().allMatch(
+ (orECls) -> supportedClasses.stream().anyMatch((suCls) -> orECls.getInstanceClass().equals(suCls))));
+ }
+
+ /**
+ * Checks whether api.waitForMark(key, task) works as intended
+ */
+ @Test
+ public void testAPI_WaitForMark_SingleKey() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var key = new Object();
+ final var waitForMarkRan = new boolean[] { false };
+
+ api.waitForMark(key, () -> waitForMarkRan[0] = true);
+ Assertions.assertFalse(waitForMarkRan[0]);
+ api.newModule().markCurrentElement(key);
+ Assertions.assertTrue(waitForMarkRan[0]);
+ }
+
+ /**
+ * Checks whether api.waitForMark(keyArray, task) works as intended
+ */
+ @Test
+ public void testAPI_WaitForMark_KeyArray() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var key1 = new Object();
+ var key2 = new Object();
+ final var waitForMarkRan = new boolean[] { false };
+
+ api.waitForMark(new Object[] { key1, key2 }, () -> waitForMarkRan[0] = true);
+ Assertions.assertFalse(waitForMarkRan[0]);
+ api.newModule().markCurrentElement(key1);
+ Assertions.assertFalse(waitForMarkRan[0]);
+ api.newModule().markCurrentElement(key2);
+ Assertions.assertTrue(waitForMarkRan[0]);
+ }
+
+ /**
+ * Checks whether api.waitForMark(keyCol, task) works as intended.
+ */
+ @Test
+ public void testAPI_WaitForMark_KeyCollection() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var key1 = new Object();
+ var key2 = new Object();
+ final var waitForMarkRan = new boolean[] { false };
+
+ api.waitForMark(List.of(key1, key2), () -> waitForMarkRan[0] = true);
+ Assertions.assertFalse(waitForMarkRan[0]);
+ api.newModule().markCurrentElement(key1);
+ Assertions.assertFalse(waitForMarkRan[0]);
+ api.newModule().markCurrentElement(key2);
+ Assertions.assertTrue(waitForMarkRan[0]);
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIWithTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIWithTest.java
new file mode 100644
index 0000000000..5f75076fa9
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPIRootAPIWithTest.java
@@ -0,0 +1,245 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.emftext.language.java.classifiers.ClassifiersPackage;
+import org.emftext.language.java.commons.CommonsPackage;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+import cipm.consistency.fluentapi.test.FluentAPITestUtils;
+
+/**
+ * A test class for the modification methods of the fluent api class:
+ * xWithFeat(...), xWithoutFeat(...), xWithAddedFeat(...),
+ * xWithRemovedFeat(...), xCleanFeat().
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPIWithTest extends AbstractFluentAPITest {
+ private static final EStructuralFeature nameFeat = CommonsPackage.Literals.NAMED_ELEMENT__NAME;
+ private static final EStructuralFeature namespaceFeat = CommonsPackage.Literals.NAMESPACE_AWARE_ELEMENT__NAMESPACES;
+ private static final EStructuralFeature extendsFeat = ClassifiersPackage.Literals.CLASS__EXTENDS;
+
+ /**
+ * Checks whether api.xWithFeat() works as intended on EAttributes.
+ */
+ @Test
+ public void testAPI_WithFeat_EAttribute() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsName = "cls";
+ var cls = api.createNewClass();
+
+ Assertions.assertNotEquals(clsName, cls.getName());
+ api.xWithFeat(cls, nameFeat, clsName);
+ Assertions.assertEquals(clsName, cls.getName());
+ }
+
+ /**
+ * Checks whether api.xWithFeat() works as intended on EReferences.
+ */
+ @Test
+ public void testAPI_WithFeat_EReference() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var extType = api.createNewClassifierReference();
+ var cls = api.createNewClass();
+
+ api.xWithFeat(cls, extendsFeat, extType);
+ Assertions.assertSame(extType, cls.getExtends());
+ }
+
+ /**
+ * Checks whether api.xWithoutFeat() works as intended on EAttributes.
+ */
+ @Test
+ public void testAPI_WithoutFeat_EAttribute() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsName = "cls";
+ var cls = api.createNewClass();
+ var feat = nameFeat;
+
+ cls.setName(clsName);
+
+ Assertions.assertEquals(clsName, cls.getName());
+ api.xWithoutFeat(cls, feat);
+ Assertions.assertEquals(feat.getDefaultValueLiteral(), cls.getName());
+ }
+
+ /**
+ * Checks whether api.xWithFeat() works as intended on EReference.
+ */
+ @Test
+ public void testAPI_WithoutFeat_EReference() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var clsExtendsVal = api.createNewClassifierReference();
+ var cls = api.createNewClass();
+ var feat = extendsFeat;
+
+ cls.setExtends(clsExtendsVal);
+
+ Assertions.assertSame(clsExtendsVal, cls.getExtends());
+ api.xWithoutFeat(cls, feat);
+ Assertions.assertEquals(feat.getDefaultValue(), cls.getExtends());
+ }
+
+ /**
+ * Checks whether api.xWithAddedFeat(val) works as intended on many-valued
+ * features without any pre-existing values.
+ */
+ @Test
+ public void testAPI_WithAddedFeat_SingleValue_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var ns = "ns";
+
+ api.xWithAddedFeat(pac, namespaceFeat, ns);
+ Assertions.assertEquals(1, pac.getNamespaces().size());
+ Assertions.assertEquals(ns, pac.getNamespaces().get(0));
+ }
+
+ /**
+ * Checks whether api.xWithAddedFeat(val) works as intended on many-valued
+ * features with pre-existing values.
+ */
+ @Test
+ public void testAPI_WithAddedFeat_SingleValue_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var pastNss = List.of("someNs1", "someNs2");
+ pac.getNamespaces().addAll(pastNss);
+ var newNs = "newNs";
+
+ var expectedNss = List.of(pastNss.get(0), pastNss.get(1), newNs);
+
+ api.xWithAddedFeat(pac, namespaceFeat, newNs);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, pac.getNamespaces());
+ }
+
+ /**
+ * Checks whether api.xWithAddedFeat(valArray) works as intended on many-valued
+ * features.
+ */
+ @Test
+ public void testAPI_WithAddedFeat_MultipleValuesAsArray() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var nss = new String[] { "ns1", "ns2" };
+
+ api.xWithAddedFeat(pac, namespaceFeat, nss);
+ FluentAPITestUtils.assertPairwiseEqual(nss, pac.getNamespaces());
+ }
+
+ /**
+ * Checks whether api.xWithAddedFeat(valCollection) works as intended on
+ * many-valued features.
+ */
+ @Test
+ public void testAPI_WithAddedFeat_MultipleValuesAsCollection() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var nss = List.of("ns1", "ns2");
+
+ api.xWithAddedFeat(pac, namespaceFeat, nss);
+ FluentAPITestUtils.assertPairwiseEqual(nss, pac.getNamespaces());
+ }
+
+ /**
+ * Checks whether api.xWithRemovedFeat(val) works as intended on many-valued
+ * features without any pre-existing values.
+ */
+ @Test
+ public void testAPI_WithRemovedFeat_SingleValue_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var ns = "ns";
+
+ api.xWithRemovedFeat(pac, namespaceFeat, ns);
+ Assertions.assertEquals(0, pac.getNamespaces().size());
+ }
+
+ /**
+ * Checks whether api.xWithRemovedFeat(val) works as intended on many-valued
+ * features with pre-existing values.
+ */
+ @Test
+ public void testAPI_WithRemovedFeat_SingleValue_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var pastNss = List.of("someNs1", "someNs2");
+ pac.getNamespaces().addAll(pastNss);
+ var nsToBeRemoved = pastNss.get(0);
+
+ var expectedNss = List.of(pastNss.get(1));
+
+ api.xWithRemovedFeat(pac, namespaceFeat, nsToBeRemoved);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, pac.getNamespaces());
+ }
+
+ /**
+ * Checks whether api.xWithRemovedFeat(valCollection) works as intended on
+ * many-valued features.
+ */
+ @Test
+ public void testAPI_WithRemovedFeat_MultipleValuesAsCollection() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var pastNss = List.of("ns1", "ns2", "ns3");
+ pac.getNamespaces().addAll(pastNss);
+ var nss = List.of(pastNss.get(0), pastNss.get(2));
+
+ api.xWithRemovedFeat(pac, namespaceFeat, nss);
+ FluentAPITestUtils.assertPairwiseEqual(List.of(pastNss.get(1)), pac.getNamespaces());
+ }
+
+ /**
+ * Checks whether api.xWithRemovedFeat(valArray) works as intended on
+ * many-valued features.
+ */
+ @Test
+ public void testAPI_WithRemovedFeat_MultipleValuesAsArray() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var pastNss = new String[] { "ns1", "ns2", "ns3" };
+ pac.getNamespaces().addAll(List.of(pastNss));
+
+ api.xWithRemovedFeat(pac, namespaceFeat, List.of(pastNss[0], pastNss[2]));
+ FluentAPITestUtils.assertPairwiseEqual(List.of(pastNss[1]), pac.getNamespaces());
+ }
+
+ /**
+ * Checks whether api.xCleanFeat() works as intended on many-valued features
+ * without any pre-existing values.
+ */
+ @Test
+ public void testAPI_CleanFeat_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+
+ Assertions.assertEquals(0, pac.getNamespaces().size());
+ api.xCleanFeat(pac, namespaceFeat);
+ Assertions.assertEquals(0, pac.getNamespaces().size());
+ }
+
+ /**
+ * Checks whether api.xCleanFeat() works as intended on many-valued features
+ * with pre-existing values.
+ */
+ @Test
+ public void testAPI_CleanFeat_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var pac = api.newPackage().createNow();
+ var pastNss = new String[] { "ns1", "ns2", "ns3" };
+ pac.getNamespaces().addAll(List.of(pastNss));
+
+ FluentAPITestUtils.assertPairwiseEqual(pastNss, pac.getNamespaces());
+ api.xCleanFeat(pac, namespaceFeat);
+ Assertions.assertEquals(0, pac.getNamespaces().size());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPISuperInitWithTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPISuperInitWithTest.java
new file mode 100644
index 0000000000..7a22a5f8ad
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/FluentAPISuperInitWithTest.java
@@ -0,0 +1,340 @@
+package cipm.consistency.fluentapi.java.test;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.emftext.language.java.commons.CommonsPackage;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.test.AbstractFluentAPITest;
+import cipm.consistency.fluentapi.test.FluentAPITestUtils;
+
+/**
+ * A test class containing tests for modification methods of the abstract
+ * (super) initialisation class within the fluent api model.
+ *
+ *
+ * Although those modification methods are also accessible under the concrete
+ * initialisations, they are not intended to be used from the concrete
+ * initialisations.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPISuperInitWithTest extends AbstractFluentAPITest {
+ private static final EStructuralFeature nameFeat = CommonsPackage.Literals.NAMED_ELEMENT__NAME;
+ private static final EStructuralFeature namespaceFeat = CommonsPackage.Literals.NAMESPACE_AWARE_ELEMENT__NAMESPACES;
+
+ /**
+ * Checks whether superInit.xWithFeat(feat, val) works as intended.
+ */
+ @Test
+ public void testSuperInit_WithFeat() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var name = "cuName";
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ Assertions.assertNull(cu.getName());
+
+ init.xWithFeat(nameFeat, name);
+ Assertions.assertEquals(name, cu.getName());
+ }
+
+ /**
+ * Checks whether superInit.xWithoutFeat(feat, val) works as intended.
+ */
+ @Test
+ public void testSuperInit_WithoutFeat() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var name = "cuName";
+ var cu = api.createNewCompilationUnit();
+ cu.setName(name);
+ var init = api.modifyX(cu);
+ Assertions.assertEquals(name, cu.getName());
+
+ init.xWithoutFeat(nameFeat);
+ Assertions.assertNull(cu.getName());
+ }
+
+ /**
+ * Checks whether superInit.xWithRemovedFeat(feat, val) works as intended, if
+ * val is not an eligible value.
+ */
+ @Test
+ public void testSuperInit_WithRemovedFeat_RemoveNonExistentValue() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithRemovedFeat(namespaceFeat, "ns4");
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithRemovedFeat(feat, val) works as intended.
+ */
+ @Test
+ public void testSuperInit_WithRemovedFeat_SingularParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+ var expectedNss = List.of(ns2, ns3);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithRemovedFeat(namespaceFeat, ns1);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithRemovedFeat(feat, valArray) works as intended.
+ */
+ @Test
+ public void testSuperInit_WithRemovedFeat_ArrayParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+ var toRemove = new String[] { ns1, ns3 };
+ var expectedNss = List.of(ns2);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithRemovedFeat(namespaceFeat, toRemove);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithRemovedFeat(feat, valArray) works as intended,
+ * if valArray were empty.
+ */
+ @Test
+ public void testSuperInit_WithRemovedFeat_EmptyArrayParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ init.xWithRemovedFeat(namespaceFeat, new String[] {});
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+
+ /**
+ * Checks whether superInit.xWithRemovedFeat(feat, valCollection) works as
+ * intended.
+ */
+ @Test
+ public void testSuperInit_WithRemovedFeat_CollectionParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+ var toRemove = List.of(ns1, ns3);
+ var expectedNss = List.of(ns2);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithRemovedFeat(namespaceFeat, toRemove);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithRemovedFeat(feat, valCollection) works as
+ * intended, if valCollection were empty.
+ */
+ @Test
+ public void testSuperInit_WithRemovedFeat_EmptyCollectionParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ init.xWithRemovedFeat(namespaceFeat, List.of());
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+
+ /**
+ * Checks whether superInit.xCleanFeat(feat) works as intended.
+ */
+ @Test
+ public void testSuperInit_CleanFeat() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ var ns1 = "ns1";
+ var ns2 = "ns2";
+ var ns3 = "ns3";
+
+ var nss = new String[] { ns1, ns2, ns3 };
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(List.of(nss));
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xCleanFeat(namespaceFeat);
+ Assertions.assertEquals(0, cu.getNamespaces().size());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, val) works as intended, if
+ * there were no prior values.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_SingularParameter_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var ns = "ns";
+
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+
+ init.xWithAddedFeat(namespaceFeat, ns);
+ Assertions.assertEquals(1, cu.getNamespaces().size());
+ Assertions.assertEquals(ns, cu.getNamespaces().get(0));
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, val) works as intended, if
+ * there were prior values.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_SingularParameter_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+ var nsToAdd = "ns";
+ var expectedNss = List.of("ns1", "ns2", nsToAdd);
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(nss);
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithAddedFeat(namespaceFeat, nsToAdd);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, valArray) works as intended, if
+ * there were no prior values.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_ArrayParameter_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = new String[] { "ns1", "ns2" };
+
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+
+ init.xWithAddedFeat(namespaceFeat, nss);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, valArray) works as intended, if
+ * there were prior values.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_ArrayParameter_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+ var nssToAdd = new String[] { "ns3", "ns4" };
+ var expectedNss = List.of("ns1", "ns2", "ns3", "ns4");
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(nss);
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithAddedFeat(namespaceFeat, nssToAdd);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, valArray) works as intended, if
+ * valArray were empty.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_EmptyArrayParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ init.xWithAddedFeat(namespaceFeat, new String[] {});
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, valCollection) works as
+ * intended, if there were no prior values.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_CollectionParameter_NoPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+
+ init.xWithAddedFeat(namespaceFeat, nss);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, valCollection) works as
+ * intended, if there were prior values.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_CollectionParameter_WithPriorValues() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var nss = List.of("ns1", "ns2");
+ var nssToAdd = List.of("ns3", "ns4");
+ var expectedNss = List.of("ns1", "ns2", "ns3", "ns4");
+
+ var cu = api.createNewCompilationUnit();
+ cu.getNamespaces().addAll(nss);
+ var init = api.modifyX(cu);
+ FluentAPITestUtils.assertPairwiseEqual(nss, cu.getNamespaces());
+
+ init.xWithAddedFeat(namespaceFeat, nssToAdd);
+ FluentAPITestUtils.assertPairwiseEqual(expectedNss, cu.getNamespaces());
+ }
+
+ /**
+ * Checks whether superInit.xWithAddedFeat(feat, valCollection) works as
+ * intended, if valCollection were empty.
+ */
+ @Test
+ public void testSuperInit_WithAddedFeat_EmptyCollectionParameter() {
+ var api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+ var cu = api.createNewCompilationUnit();
+ var init = api.modifyX(cu);
+ init.xWithAddedFeat(namespaceFeat, List.of());
+ Assertions.assertTrue(cu.getNamespaces().isEmpty());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIInitialisationGenerationTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIInitialisationGenerationTest.java
new file mode 100644
index 0000000000..3abd922ece
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIInitialisationGenerationTest.java
@@ -0,0 +1,14 @@
+package cipm.consistency.fluentapi.java.test.metamodel;
+
+import cipm.consistency.fluentapi.test.metamodel.AbstractFluentAPIInitialisationGenerationTest;
+
+/**
+ * Implementation of {@link AbstractFluentAPIInitialisationGenerationTest} for
+ * JaMoPP.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIInitialisationGenerationTest extends AbstractFluentAPIInitialisationGenerationTest
+ implements IFluentJavaAPIMetamodelTest {
+
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIMetamodelCoverageTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIMetamodelCoverageTest.java
new file mode 100644
index 0000000000..e582937d9e
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIMetamodelCoverageTest.java
@@ -0,0 +1,12 @@
+package cipm.consistency.fluentapi.java.test.metamodel;
+
+import cipm.consistency.fluentapi.test.metamodel.AbstractFluentAPIMetamodelCoverageTest;
+
+/**
+ * Implementation of {@link AbstractFluentAPIMetamodelCoverageTest} for JaMoPP.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIMetamodelCoverageTest extends AbstractFluentAPIMetamodelCoverageTest
+ implements IFluentJavaAPIMetamodelTest {
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIRootAPIGenerationTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIRootAPIGenerationTest.java
new file mode 100644
index 0000000000..7268c5680f
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/FluentAPIRootAPIGenerationTest.java
@@ -0,0 +1,13 @@
+package cipm.consistency.fluentapi.java.test.metamodel;
+
+import cipm.consistency.fluentapi.test.metamodel.AbstractFluentAPIRootAPIGenerationTest;
+
+/**
+ * Implementation of {@link AbstractFluentAPIRootAPIGenerationTest} for JaMoPP.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPIGenerationTest extends AbstractFluentAPIRootAPIGenerationTest
+ implements IFluentJavaAPIMetamodelTest {
+
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/IFluentJavaAPIMetamodelTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/IFluentJavaAPIMetamodelTest.java
new file mode 100644
index 0000000000..816d4565ee
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/IFluentJavaAPIMetamodelTest.java
@@ -0,0 +1,199 @@
+package cipm.consistency.fluentapi.java.test.metamodel;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import cipm.consistency.fluentapi.java.api.ApiFactory;
+import cipm.consistency.fluentapi.java.api.FluentAPISuperInitialisation;
+import cipm.consistency.fluentapi.java.api.FluentJavaAPI;
+import cipm.consistency.fluentapi.java.metamodel.FluentAPIJavaMetamodelFilter;
+import cipm.consistency.fluentapi.java.metamodel.FluentAPIJavaMetamodelPackageProvider;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.test.metamodel.IFluentAPIMetamodelTest;
+
+/**
+ * An extension of {@link IFluentAPIMetamodelTest} for JaMoPP.
+ *
+ * @author Alp Torac Genc
+ */
+public interface IFluentJavaAPIMetamodelTest extends IFluentAPIMetamodelTest {
+ static final FluentAPITargetMetamodelFilter filter = new FluentAPIJavaMetamodelFilter();
+ static final FluentAPITargetMetamodelPackageProvider metamodelProvider = new FluentAPIJavaMetamodelPackageProvider();
+ static final FluentJavaAPI api = ApiFactory.eINSTANCE.createFluentJavaAPI();
+
+ private static FluentAPISuperInitialisation toSupInit(EObject init) {
+ return (FluentAPISuperInitialisation) init;
+ }
+
+ @Override
+ public default FluentAPITargetMetamodelPackageProvider getProvider() {
+ return metamodelProvider;
+ }
+
+ @Override
+ public default FluentAPITargetMetamodelFilter getFilter() {
+ return filter;
+ }
+
+ @Override
+ public default EObject init_getCurrentElement(EObject init) {
+ return toSupInit(init).getCurrentElement();
+ }
+
+ @Override
+ public default void init_mark(EObject init, Object key) {
+ toSupInit(init).markCurrentElement(key);
+ }
+
+ @Override
+ public default EObject init_unmark(EObject init, Object key) {
+ return toSupInit(init).unmarkCurrentElement(key);
+ }
+
+ @Override
+ public default EObject init_createNow(EObject init) {
+ return toSupInit(init).createNow();
+ }
+
+ @Override
+ public default EObject api_newX(EClass eCls) {
+ return api.newX(eCls);
+ }
+
+ @Override
+ public default EObject api_newX_createNow(EClass eCls) {
+ return api.newX(eCls).createNow();
+ }
+
+ @Override
+ public default EObject api_newX_createNow(Class> cls) {
+ return api.newX(cls).createNow();
+ }
+
+ @Override
+ public default EObject api_createNewX(Class> cls) {
+ return (EObject) api.createNewX(cls);
+ }
+
+ @Override
+ public default EObject api_modifyX(EObject obj) {
+ return api.modifyX(obj);
+ }
+
+ @Override
+ public default EObject api_modifyX_createNow(EObject obj) {
+ return api.modifyX(obj).createNow();
+ }
+
+ @Override
+ public default void api_modifyX_xWithAddedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.modifyX(obj).xWithAddedFeat(feat, val);
+ }
+
+ @Override
+ public default void api_modifyX_xWithRemovedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.modifyX(obj).xWithRemovedFeat(feat, val);
+ }
+
+ @Override
+ public default void api_modifyX_xCleanFeat(EObject obj, EStructuralFeature feat) {
+ api.modifyX(obj).xCleanFeat(feat);
+ }
+
+ @Override
+ public default void api_modifyX_xWithFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.modifyX(obj).xWithFeat(feat, val);
+ }
+
+ @Override
+ public default void api_modifyX_xWithoutFeat(EObject obj, EStructuralFeature feat) {
+ api.modifyX(obj).xWithoutFeat(feat);
+ }
+
+ @Override
+ public default EClass api_getInitialisationForX_getInitialisedEClass(Class> cls) {
+ return api.getInitialisationForX(cls).getInitialisedEClass();
+ }
+
+ @Override
+ public default EClass api_getInitialisationForX_getInitialisedEClass(EClass cls) {
+ return api.getInitialisationForX(cls).getInitialisedEClass();
+ }
+
+ @Override
+ public default EClass api_getInitialisationForX_getInitialisedEClass(EObject obj) {
+ return api.getInitialisationForX(obj).getInitialisedEClass();
+ }
+
+ @Override
+ public default EObject api_continueX(Class> cls) {
+ return api.continueX(cls);
+ }
+
+ @Override
+ public default void api_xWithFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.xWithFeat(obj, feat, val);
+ }
+
+ @Override
+ public default void api_xWithoutFeat(EObject obj, EStructuralFeature feat) {
+ api.xWithoutFeat(obj, feat);
+ }
+
+ @Override
+ public default void api_xWithAddedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.xWithAddedFeat(obj, feat, val);
+ }
+
+ @Override
+ public default void api_xWithRemovedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.xWithRemovedFeat(obj, feat, val);
+ }
+
+ @Override
+ public default void api_xCleanFeat(EObject obj, EStructuralFeature feat) {
+ api.xCleanFeat(obj, feat);
+ }
+
+ @Override
+ public default void api_mark(Object key, EObject val) {
+ api.mark(key, val);
+ }
+
+ @Override
+ public default EObject api_unmark(Object key) {
+ return api.unmark(key);
+ }
+
+ @Override
+ public default EObject api_unmark(Object key, EObject val) {
+ return api.unmark(key, val);
+ }
+
+ @Override
+ public default EObject api_getMarkedX(Object key) {
+ return api.getMarkedX(key);
+ }
+
+ @Override
+ public default EObject api_modifyMarkedX(Object key) {
+ return api.modifyMarkedX(key);
+ }
+
+ @Override
+ public default EObject api_continueMarkedX(Object key) {
+ return api.continueMarkedX(key);
+ }
+
+ @Override
+ public default EObject getAPI() {
+ return api;
+ }
+
+ @Override
+ public default EObject api_getInitialisationForX(EClass eCls) {
+ return api.getInitialisationForX(eCls);
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/package-info.java
new file mode 100644
index 0000000000..8e704f2af7
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/metamodel/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains implementations of {@link cipm.consistency.fluentapi.test.metamodel}
+ * for JaMoPP.
+ */
+package cipm.consistency.fluentapi.java.test.metamodel;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/package-info.java
new file mode 100644
index 0000000000..088563cb9e
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.java/src/cipm/consistency/fluentapi/java/test/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains tests for the generated fluent api for JaMoPP.
+ */
+package cipm.consistency.fluentapi.java.test;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.classpath b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.classpath
new file mode 100644
index 0000000000..bbfe5b0e61
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.project b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.project
new file mode 100644
index 0000000000..0c4458c6f0
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.project
@@ -0,0 +1,28 @@
+
+
+ cipm.consistency.fluentapi.pcm
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.settings/org.eclipse.jdt.core.prefs b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..c9545f06a4
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/META-INF/MANIFEST.MF b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..4264bf8570
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/META-INF/MANIFEST.MF
@@ -0,0 +1,38 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: cipm.consistency.fluentapi.pcm;singleton:=true
+Bundle-Version: 0.2.0.qualifier
+Bundle-ClassPath: .
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Export-Package: cipm.consistency.fluentapi.pcm.api,
+ cipm.consistency.fluentapi.pcm.api.impl,
+ cipm.consistency.fluentapi.pcm.api.inits,
+ cipm.consistency.fluentapi.pcm.api.inits.impl,
+ cipm.consistency.fluentapi.pcm.api.inits.util,
+ cipm.consistency.fluentapi.pcm.api.placeholderTypes,
+ cipm.consistency.fluentapi.pcm.api.placeholderTypes.impl,
+ cipm.consistency.fluentapi.pcm.api.util,
+ cipm.consistency.fluentapi.pcm.builder,
+ cipm.consistency.fluentapi.pcm.metamodel,
+ cipm.consistency.fluentapi.pcm.test,
+ cipm.consistency.fluentapi.pcm.test.metamodel
+Automatic-Module-Name: cipm.consistency.fluentapi.pcm
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Require-Bundle: cipm.consistency.fluentapi,
+ junit-jupiter-api,
+ junit-jupiter-engine,
+ junit-jupiter-params,
+ org.apache.log4j,
+ org.eclipse.emf.codegen.ecore,
+ org.eclipse.core.runtime,
+ org.eclipse.emf.ecore;visibility:=reexport,
+ org.eclipse.emf.ecore.xmi;visibility:=reexport,
+ org.apache.commons.lang,
+ org.palladiosimulator.pcm;visibility:=reexport,
+ de.uka.ipd.sdq.stoex;visibility:=reexport,
+ de.uka.ipd.sdq.units;visibility:=reexport,
+ de.uka.ipd.sdq.identifier;visibility:=reexport,
+ de.uka.ipd.sdq.probfunction;visibility:=reexport
+Bundle-ActivationPolicy: lazy
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/README.md b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/README.md
new file mode 100644
index 0000000000..6e2ad8a299
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/README.md
@@ -0,0 +1,7 @@
+# Fluent API for PCM
+
+This plug-in contains the implementation of the fluent API generation for PCM and considers the [(EMF-based) PCM metamodel](https://github.com/PalladioSimulator/Palladio-Core-PCM/blob/master/bundles/org.palladiosimulator.pcm/model/pcm.ecore). The generated fluent api for PCM will consider the entirety of the 'pcm' package.
+
+The fluent API class within this plug-in is called [FluentPcmAPI](./src-gen/cipm.consistency.fluentapi.pcm.api/FluentPcmAPI.java). Note that this class is not present in this plug-in by default will be generated from the fluent API model.
+
+For exemplary usage, refer to the test cases within the [test package of this plug-in](./src/cipm.consistency.fluentapi.pcm.test). For further details, refer to the [base plug-in for fluent API generation](../cipm.consistency.fluentapi/README.md).
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/build.properties b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/build.properties
new file mode 100644
index 0000000000..29969d1711
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/build.properties
@@ -0,0 +1,11 @@
+#
+
+bin.includes = .,\
+ metamodel/,\
+ META-INF/,\
+ plugin.xml,\
+ plugin.properties
+jars.compile.order = .
+source.. = src-gen/,\
+ src/
+output.. = bin/
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/plugin.properties b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/plugin.properties
new file mode 100644
index 0000000000..513cf17f1a
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/plugin.properties
@@ -0,0 +1,4 @@
+#
+
+pluginName = pcm-fluentapi Model
+providerName = MCSE, KIT
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/plugin.xml b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/plugin.xml
new file mode 100644
index 0000000000..d95d42bd5b
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/plugin.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/builder/FluentPCMAPIBuilder.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/builder/FluentPCMAPIBuilder.java
new file mode 100644
index 0000000000..05f5a76025
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/builder/FluentPCMAPIBuilder.java
@@ -0,0 +1,88 @@
+package cipm.consistency.fluentapi.pcm.builder;
+
+import java.util.ArrayList;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelFactory;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import cipm.consistency.fluentapi.builder.FluentAPIAbstractBuilder;
+import cipm.consistency.fluentapi.gen.FluentAPIGenerationContext;
+import cipm.consistency.fluentapi.gen.FluentAPIGenerator;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.pcm.metamodel.FluentAPIPcmMetamodelFilter;
+import cipm.consistency.fluentapi.pcm.metamodel.FluentAPIPcmMetamodelPackageProvider;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationBigNumberParameterPostProcessor;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationForEachOverloadPostProcessor;
+import cipm.consistency.fluentapi.postprocessor.FluentAPIGenerationMultipleValueParameterSameMethodBodyOverloadPostProcessor;
+
+/**
+ * An implementation of {@link FluentAPIAbstractBuilder} for the PCM metamodel.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentPCMAPIBuilder extends FluentAPIAbstractBuilder {
+ private static final FluentAPITargetMetamodelPackageProvider provider = new FluentAPIPcmMetamodelPackageProvider();
+ private static final FluentAPITargetMetamodelFilter filter = new FluentAPIPcmMetamodelFilter();
+
+ @Override
+ protected GenModel generateGenModel(Resource genModelRes, Resource ecoreRes, FluentAPIGenerationContext context) {
+ var genModel = GenModelFactory.eINSTANCE.createGenModel();
+ genModelRes.getContents().add(genModel);
+
+ genModel.setModelDirectory("/" + getGeneratedFluentAPIModelDirectoryPath().toString());
+ genModel.setOperationReflection(true);
+ genModel.setImportOrganizing(true);
+ genModel.setComplianceLevel(getJDKVersion());
+ genModel.setModelName(getModelName());
+ genModel.setModelPluginID(getModelPluginID());
+ genModel.getForeignModel().add(ecoreRes.getURI().lastSegment());
+
+ var targetMetamodelGenModel = provider.getTargetMetamodelGenModels().get(0);
+ genModel.getUsedGenPackages().addAll(targetMetamodelGenModel.getGenPackages());
+
+ var initEPacs = new ArrayList();
+ var toGen = (EPackage) ecoreRes.getContents().get(0);
+
+ initEPacs.add(toGen);
+ genModel.initialize(initEPacs);
+
+ genModel.reconcile();
+
+ genModel.setCanGenerate(true);
+
+ var apiGenPac = genModel.findGenPackage(toGen);
+ apiGenPac.setBasePackage(context.getBasePackageName());
+
+ return genModel;
+ }
+
+ @Override
+ protected void generateEcoreModel(Resource ecoreRes, FluentAPIGenerationContext context) {
+ new FluentAPIGenerator().generateRootAPIPackages(context);
+ new FluentAPIGenerationBigNumberParameterPostProcessor(context.getAllInitEClss()).apply();
+
+ var allEClss = new ArrayList();
+ allEClss.add(context.getFluentAPIECls());
+ allEClss.add(context.getInitSuperECls());
+ allEClss.addAll(context.getAllInitEClss());
+
+ new FluentAPIGenerationForEachOverloadPostProcessor(context, allEClss).apply();
+ new FluentAPIGenerationMultipleValueParameterSameMethodBodyOverloadPostProcessor(context, allEClss).apply();
+
+ ecoreRes.getContents().add(context.getRootPackage());
+ }
+
+ @Override
+ protected FluentAPITargetMetamodelPackageProvider getTargetMetamodelPackageProvider() {
+ return provider;
+ }
+
+ @Override
+ protected FluentAPITargetMetamodelFilter getTargetMetamodelFilter() {
+ return filter;
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/builder/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/builder/package-info.java
new file mode 100644
index 0000000000..b8bf5ffbac
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/builder/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains the builder class, which is responsible for building the fluent api
+ * model (for PCM) that consists of an ecore and a genmodel file.
+ */
+package cipm.consistency.fluentapi.pcm.builder;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/FluentAPIPcmMetamodelFilter.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/FluentAPIPcmMetamodelFilter.java
new file mode 100644
index 0000000000..03b453ff65
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/FluentAPIPcmMetamodelFilter.java
@@ -0,0 +1,44 @@
+package cipm.consistency.fluentapi.pcm.metamodel;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+
+/**
+ * An implementation of {@link FluentAPITargetMetamodelFilter} for PCM.
+ *
+ *
+ * Excludes the features ( {@link EStructuralFeature} ) that are present in
+ * {@link EObject} and its super-types. All other EClasses and features under
+ * the {@link PcmPackage} are included.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIPcmMetamodelFilter extends FluentAPITargetMetamodelFilter {
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * Excludes the features ( {@link EStructuralFeature} ) that are present in
+ * {@link EObject} and its super-types. All other features under the
+ * {@link PcmPackage} are included.
+ */
+ @Override
+ public boolean isFeatureEligible(EClass holderOfFeat, EStructuralFeature feat) {
+ return isFeatureChangeable(feat)
+ && !feat.getEContainingClass().getName().equals(EcorePackage.Literals.EOBJECT.getName());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * All EClasses under the {@link PcmPackage} are included.
+ */
+ @Override
+ public boolean isEClassEligible(EClass eCls) {
+ return true;
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/FluentAPIPcmMetamodelPackageProvider.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/FluentAPIPcmMetamodelPackageProvider.java
new file mode 100644
index 0000000000..bcbd8029d3
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/FluentAPIPcmMetamodelPackageProvider.java
@@ -0,0 +1,145 @@
+package cipm.consistency.fluentapi.pcm.metamodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.palladiosimulator.pcm.PcmPackage;
+
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.metamodel.MetamodelUtil;
+
+/**
+ * An implementation of {@link FluentAPITargetMetamodelPackageProvider} for PCM.
+ *
+ *
+ * This class internally "fixes" the Ecore and GenModel of JaMoPP that it
+ * parses, in order to avoid having duplicated Resource instances during fluent
+ * api generation. This is due to Eclipse plug-in limitations.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIPcmMetamodelPackageProvider extends FluentAPITargetMetamodelPackageProvider {
+ /**
+ * The (plug-in based) URI to PCM's genmodel file
+ */
+ private static final URI pcmMetamodelGenModelURI = URI
+ .createURI("platform:/plugin/org.palladiosimulator.pcm/model/pcm.genmodel");
+ /**
+ * The (plug-in based) URI to PCM's ecore file
+ */
+ private static final URI pcmMetamodelEcoreModelURI = URI
+ .createURI("platform:/plugin/org.palladiosimulator.pcm/model/pcm.ecore");
+
+ /**
+ * The ResourceSet, which will contain the Resources of the GenModel and the
+ * Ecore model parsed by this class ( {@link #ecoreRes} and {@link #genModelRes}
+ * ). Note that those Resources are not the original Resources of the JaMoPP
+ * model.
+ */
+ private final ResourceSet metamodelResSet = new ResourceSetImpl();
+ /**
+ * The Resource instance containing the parsed Ecore model of PCM. This is NOT
+ * the Resource instance of {@code PcmPackage.eINSTANCE}.
+ */
+ private Resource ecoreRes;
+ /**
+ * The Resource instance containing the parsed GenModel of PCM. This does NOT
+ * use the Resource instance of {@code PcmPackage.eINSTANCE}, but
+ * {@link #ecoreRes}.
+ */
+ private Resource genModelRes;
+ /**
+ * The list containing the original PCM EClasses that are available under
+ * {@code PcmPackage.eINSTANCE}. These EClasses are NOT the same as those in
+ * {@link #ecoreRes}.
+ */
+ private List originalEClss;
+
+ /**
+ * Caches the (original) EClasses found under the PCM metamodel ( under
+ * {@code PcmPackage.eINSTANCE} ) in {@link #originalEClss}, in order to spare
+ * constantly retrieving them from the Resource instances.
+ */
+ private void cacheOriginalEClasses() {
+ if (originalEClss == null) {
+ originalEClss = new ArrayList(MetamodelUtil.getAllEClasses(PcmPackage.eINSTANCE));
+ }
+ }
+
+ @Override
+ public String getTargetMetamodelName() {
+ var topPac = getTargetMetamodelEcoreEPackages().get(0);
+ return topPac.getName();
+ }
+
+ @Override
+ public List getAllTargetMetamodelEClasses() {
+ var topPac = getTargetMetamodelEcoreEPackages().get(0);
+ return List.copyOf(MetamodelUtil.getAllEClasses(topPac));
+ }
+
+ @Override
+ public List getAllEClassesInOriginalMetamodel() {
+ cacheOriginalEClasses();
+ return originalEClss;
+ }
+
+ @Override
+ public List getTargetMetamodelGenModels() {
+ if (genModelRes == null) {
+ genModelRes = metamodelResSet.getResource(pcmMetamodelGenModelURI, true);
+ }
+
+ var pcmGenModel = (GenModel) genModelRes.getContents().get(0);
+ pcmGenModel.setCanGenerate(false);
+
+ return List.of(pcmGenModel);
+ }
+
+ @Override
+ public List getTargetMetamodelEcoreEPackages() {
+ if (ecoreRes == null) {
+ ecoreRes = metamodelResSet.getResource(pcmMetamodelEcoreModelURI, true);
+ var parsedPcmPac = (EPackage) ecoreRes.getContents().get(0);
+ fixInstanceClasses(parsedPcmPac);
+ }
+
+ return List.of((EPackage) ecoreRes.getContents().get(0));
+ }
+
+ /**
+ * Changes the instance classes within the EClasses under parsedPcmPac to the
+ * original EClasses from PCM ( {@link #originalEClss} ).
+ *
+ * @param parsedPcmPac The Ecore model of PCM, which has been parsed by this
+ * class.
+ */
+ private void fixInstanceClasses(EPackage parsedPcmPac) {
+ var parsedEClss = MetamodelUtil.getAllEClasses(parsedPcmPac);
+ cacheOriginalEClasses();
+
+ if (parsedEClss.size() != originalEClss.size())
+ throw new IllegalStateException(
+ "Parsed PCM package and the actual PCM package contain different amounts of EClasses");
+
+ for (var parsedECls : parsedEClss) {
+ var matchingActualECls = originalEClss.stream()
+ .filter((cls) -> cls.getEPackage().getName().equals(parsedECls.getEPackage().getName()))
+ .filter((cls) -> cls.getName().equals(parsedECls.getName())).toArray(EClass[]::new);
+ if (matchingActualECls.length != 1)
+ throw new IllegalStateException("Unknown EClass has been parsed");
+
+ var actualECls = matchingActualECls[0];
+ parsedECls.setInstanceClassName(actualECls.getInstanceClassName());
+ parsedECls.setInstanceTypeName(actualECls.getInstanceTypeName());
+ parsedECls.setInstanceClass(actualECls.getInstanceClass());
+ }
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/package-info.java
new file mode 100644
index 0000000000..7a86c69f95
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/metamodel/package-info.java
@@ -0,0 +1 @@
+package cipm.consistency.fluentapi.pcm.metamodel;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/FluentAPIPcmManyValuedFeatureModificationTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/FluentAPIPcmManyValuedFeatureModificationTest.java
new file mode 100644
index 0000000000..e36f2165ce
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/FluentAPIPcmManyValuedFeatureModificationTest.java
@@ -0,0 +1,99 @@
+package cipm.consistency.fluentapi.pcm.test;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.palladiosimulator.pcm.core.entity.EntityPackage;
+import org.palladiosimulator.pcm.core.entity.ResourceRequiredRole;
+import org.palladiosimulator.pcm.repository.RepositoryComponent;
+import org.palladiosimulator.pcm.repository.RepositoryPackage;
+
+import cipm.consistency.fluentapi.pcm.api.ApiFactory;
+
+/**
+ * A test class containing test cases for the fluent api generated for the PCM
+ * metamodel.
+ *
+ *
+ * The main purpose of this test class is to show that many-valued feature
+ * modifications (in PCM) are not problematic in realistic cases, although they
+ * currently fail in metamodel tests of the fluent api for PCM.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIPcmManyValuedFeatureModificationTest {
+ /**
+ * Ensures that adding an array of values to a many-valued PCM feature via its
+ * initialisation class works as intended.
+ */
+ @Test
+ public void testInit_WithAddedArray() {
+ var api = ApiFactory.eINSTANCE.createFluentPcmAPI();
+ var repo = api.newRepository()
+ .withAddedComponents__Repository(
+ new RepositoryComponent[] { api.createNewBasicComponent(), api.createNewBasicComponent() })
+ .createNow();
+ Assertions.assertEquals(2, repo.getComponents__Repository().size());
+ }
+
+ /**
+ * Ensures that adding an array of values to a many-valued PCM feature via the
+ * abstract (super) initialisation class works as intended.
+ */
+ @Test
+ public void testSuperInit_WithAddedArray() {
+ var api = ApiFactory.eINSTANCE.createFluentPcmAPI();
+ var repo = api.createNewRepository();
+ api.modifyRepository(repo).xWithAddedFeat(RepositoryPackage.Literals.REPOSITORY__COMPONENTS_REPOSITORY,
+ new RepositoryComponent[] { api.createNewBasicComponent(), api.createNewBasicComponent() });
+ Assertions.assertEquals(2, repo.getComponents__Repository().size());
+ }
+
+ /**
+ * Ensures that adding an array of values to a many-valued PCM feature via the
+ * fluent api class works as intended.
+ */
+ @Test
+ public void testApi_WithAddedArray() {
+ var api = ApiFactory.eINSTANCE.createFluentPcmAPI();
+ var repo = api.createNewRepository();
+ api.xWithAddedFeat(repo, RepositoryPackage.Literals.REPOSITORY__COMPONENTS_REPOSITORY,
+ new RepositoryComponent[] { api.createNewBasicComponent(), api.createNewBasicComponent() });
+ Assertions.assertEquals(2, repo.getComponents__Repository().size());
+ }
+
+ /**
+ * This is a failing test scenario in metamodel tests for fluent api for PCM,
+ * but it works here => The initial value of
+ * NewResourceInterfaceRequiringEntity.getResourceRequiredRoles__ResourceInterfaceRequiringEntity
+ * is not appropriate
+ */
+ @Test
+ public void testApi_WithAddedArray_Failing() {
+ var api = ApiFactory.eINSTANCE.createFluentPcmAPI();
+ var obj = api.createNewResourceInterfaceRequiringEntity();
+
+ api.xWithAddedFeat(obj,
+ EntityPackage.Literals.RESOURCE_INTERFACE_REQUIRING_ENTITY__RESOURCE_REQUIRED_ROLES_RESOURCE_INTERFACE_REQUIRING_ENTITY,
+ new ResourceRequiredRole[] { api.createNewResourceRequiredRole(),
+ api.createNewResourceRequiredRole() });
+ Assertions.assertEquals(2, obj.getResourceRequiredRoles__ResourceInterfaceRequiringEntity().size());
+ }
+
+ /**
+ * This is a failing test scenario in metamodel tests for fluent api for PCM,
+ * but it works here => The initial value of
+ * NewResourceInterfaceRequiringEntity.getResourceRequiredRoles__ResourceInterfaceRequiringEntity
+ * is not appropriate
+ */
+ @Test
+ public void testSuperInit_WithAddedArray_Failing() {
+ var api = ApiFactory.eINSTANCE.createFluentPcmAPI();
+ var obj = api.createNewResourceInterfaceRequiringEntity();
+
+ api.modifyResourceInterfaceRequiringEntity(obj).xWithAddedFeat(
+ EntityPackage.Literals.RESOURCE_INTERFACE_REQUIRING_ENTITY__RESOURCE_REQUIRED_ROLES_RESOURCE_INTERFACE_REQUIRING_ENTITY,
+ new ResourceRequiredRole[] { api.createNewResourceRequiredRole(),
+ api.createNewResourceRequiredRole() });
+ Assertions.assertEquals(2, obj.getResourceRequiredRoles__ResourceInterfaceRequiringEntity().size());
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIInitialisationGenerationTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIInitialisationGenerationTest.java
new file mode 100644
index 0000000000..d65d85fe0f
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIInitialisationGenerationTest.java
@@ -0,0 +1,14 @@
+package cipm.consistency.fluentapi.pcm.test.metamodel;
+
+import cipm.consistency.fluentapi.test.metamodel.AbstractFluentAPIInitialisationGenerationTest;
+
+/**
+ * Implementation of {@link AbstractFluentAPIInitialisationGenerationTest} for
+ * PCM.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIInitialisationGenerationTest extends AbstractFluentAPIInitialisationGenerationTest
+ implements IFluentPcmAPIMetamodelTest {
+
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIMetamodelCoverageTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIMetamodelCoverageTest.java
new file mode 100644
index 0000000000..e4599dd1d4
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIMetamodelCoverageTest.java
@@ -0,0 +1,34 @@
+package cipm.consistency.fluentapi.pcm.test.metamodel;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.test.metamodel.AbstractFluentAPIMetamodelCoverageTest;
+
+/**
+ * Implementation of {@link AbstractFluentAPIMetamodelCoverageTest} for PCM.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIMetamodelCoverageTest extends AbstractFluentAPIMetamodelCoverageTest
+ implements IFluentPcmAPIMetamodelTest {
+ /**
+ * Currently PCM is having issues casting Object[] into SomePCMModelElement[],
+ * hence this test is disabled
+ */
+ @Disabled("Disabled until PCM-specific issues are dealt with")
+ @Override
+ @Test
+ public void concreteElementCoverageTest_SuperInit_xManyValuedFeature() {
+ }
+
+ /**
+ * Currently PCM is having issues casting Object[] into SomePCMModelElement[],
+ * hence this test is disabled
+ */
+ @Disabled("Disabled until PCM-specific issues are dealt with")
+ @Override
+ @Test
+ public void concreteElementCoverageTest_API_xManyValuedFeature() {
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIRootAPIGenerationTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIRootAPIGenerationTest.java
new file mode 100644
index 0000000000..acf9dad180
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/FluentAPIRootAPIGenerationTest.java
@@ -0,0 +1,20 @@
+package cipm.consistency.fluentapi.pcm.test.metamodel;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import cipm.consistency.fluentapi.test.metamodel.AbstractFluentAPIRootAPIGenerationTest;
+
+/**
+ * Implementation of {@link AbstractFluentAPIRootAPIGenerationTest} for PCM.
+ *
+ * @author Alp Torac Genc
+ */
+public class FluentAPIRootAPIGenerationTest extends AbstractFluentAPIRootAPIGenerationTest
+ implements IFluentPcmAPIMetamodelTest {
+ @Disabled("There are no elements with only one modifiable feature in PCM metamodel")
+ @Override
+ @Test
+ public void methodTest_API_NewX_WithParameter_SingleModifiableFeature() {
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/IFluentPcmAPIMetamodelTest.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/IFluentPcmAPIMetamodelTest.java
new file mode 100644
index 0000000000..a75a0136eb
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/IFluentPcmAPIMetamodelTest.java
@@ -0,0 +1,199 @@
+package cipm.consistency.fluentapi.pcm.test.metamodel;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+import cipm.consistency.fluentapi.pcm.api.ApiFactory;
+import cipm.consistency.fluentapi.pcm.api.FluentAPISuperInitialisation;
+import cipm.consistency.fluentapi.pcm.api.FluentPcmAPI;
+import cipm.consistency.fluentapi.pcm.metamodel.FluentAPIPcmMetamodelFilter;
+import cipm.consistency.fluentapi.pcm.metamodel.FluentAPIPcmMetamodelPackageProvider;
+import cipm.consistency.fluentapi.test.metamodel.IFluentAPIMetamodelTest;
+
+/**
+ * An extension of {@link IFluentAPIMetamodelTest} for PCM.
+ *
+ * @author Alp Torac Genc
+ */
+public interface IFluentPcmAPIMetamodelTest extends IFluentAPIMetamodelTest {
+ static final FluentAPITargetMetamodelFilter filter = new FluentAPIPcmMetamodelFilter();
+ static final FluentAPITargetMetamodelPackageProvider metamodelProvider = new FluentAPIPcmMetamodelPackageProvider();
+ static final FluentPcmAPI api = ApiFactory.eINSTANCE.createFluentPcmAPI();
+
+ private static FluentAPISuperInitialisation toSupInit(EObject init) {
+ return (FluentAPISuperInitialisation) init;
+ }
+
+ @Override
+ public default FluentAPITargetMetamodelPackageProvider getProvider() {
+ return metamodelProvider;
+ }
+
+ @Override
+ public default FluentAPITargetMetamodelFilter getFilter() {
+ return filter;
+ }
+
+ @Override
+ public default EObject init_getCurrentElement(EObject init) {
+ return toSupInit(init).getCurrentElement();
+ }
+
+ @Override
+ public default void init_mark(EObject init, Object key) {
+ toSupInit(init).markCurrentElement(key);
+ }
+
+ @Override
+ public default EObject init_unmark(EObject init, Object key) {
+ return toSupInit(init).unmarkCurrentElement(key);
+ }
+
+ @Override
+ public default EObject init_createNow(EObject init) {
+ return toSupInit(init).createNow();
+ }
+
+ @Override
+ public default EObject api_newX(EClass eCls) {
+ return api.newX(eCls);
+ }
+
+ @Override
+ public default EObject api_newX_createNow(EClass eCls) {
+ return api.newX(eCls).createNow();
+ }
+
+ @Override
+ public default EObject api_newX_createNow(Class> cls) {
+ return api.newX(cls).createNow();
+ }
+
+ @Override
+ public default EObject api_createNewX(Class> cls) {
+ return (EObject) api.createNewX(cls);
+ }
+
+ @Override
+ public default EObject api_modifyX(EObject obj) {
+ return api.modifyX(obj);
+ }
+
+ @Override
+ public default EObject api_modifyX_createNow(EObject obj) {
+ return api.modifyX(obj).createNow();
+ }
+
+ @Override
+ public default void api_modifyX_xWithAddedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.modifyX(obj).xWithAddedFeat(feat, val);
+ }
+
+ @Override
+ public default void api_modifyX_xWithRemovedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.modifyX(obj).xWithRemovedFeat(feat, val);
+ }
+
+ @Override
+ public default void api_modifyX_xCleanFeat(EObject obj, EStructuralFeature feat) {
+ api.modifyX(obj).xCleanFeat(feat);
+ }
+
+ @Override
+ public default void api_modifyX_xWithFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.modifyX(obj).xWithFeat(feat, val);
+ }
+
+ @Override
+ public default void api_modifyX_xWithoutFeat(EObject obj, EStructuralFeature feat) {
+ api.modifyX(obj).xWithoutFeat(feat);
+ }
+
+ @Override
+ public default EClass api_getInitialisationForX_getInitialisedEClass(Class> cls) {
+ return api.getInitialisationForX(cls).getInitialisedEClass();
+ }
+
+ @Override
+ public default EClass api_getInitialisationForX_getInitialisedEClass(EClass cls) {
+ return api.getInitialisationForX(cls).getInitialisedEClass();
+ }
+
+ @Override
+ public default EClass api_getInitialisationForX_getInitialisedEClass(EObject obj) {
+ return api.getInitialisationForX(obj).getInitialisedEClass();
+ }
+
+ @Override
+ public default EObject api_continueX(Class> cls) {
+ return api.continueX(cls);
+ }
+
+ @Override
+ public default void api_xWithFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.xWithFeat(obj, feat, val);
+ }
+
+ @Override
+ public default void api_xWithoutFeat(EObject obj, EStructuralFeature feat) {
+ api.xWithoutFeat(obj, feat);
+ }
+
+ @Override
+ public default void api_xWithAddedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.xWithAddedFeat(obj, feat, val);
+ }
+
+ @Override
+ public default void api_xWithRemovedFeat(EObject obj, EStructuralFeature feat, Object val) {
+ api.xWithRemovedFeat(obj, feat, val);
+ }
+
+ @Override
+ public default void api_xCleanFeat(EObject obj, EStructuralFeature feat) {
+ api.xCleanFeat(obj, feat);
+ }
+
+ @Override
+ public default void api_mark(Object key, EObject val) {
+ api.mark(key, val);
+ }
+
+ @Override
+ public default EObject api_unmark(Object key) {
+ return api.unmark(key);
+ }
+
+ @Override
+ public default EObject api_unmark(Object key, EObject val) {
+ return api.unmark(key, val);
+ }
+
+ @Override
+ public default EObject api_getMarkedX(Object key) {
+ return api.getMarkedX(key);
+ }
+
+ @Override
+ public default EObject api_modifyMarkedX(Object key) {
+ return api.modifyMarkedX(key);
+ }
+
+ @Override
+ public default EObject api_continueMarkedX(Object key) {
+ return api.continueMarkedX(key);
+ }
+
+ @Override
+ public default EObject getAPI() {
+ return api;
+ }
+
+ @Override
+ public default EObject api_getInitialisationForX(EClass eCls) {
+ return api.getInitialisationForX(eCls);
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/package-info.java
new file mode 100644
index 0000000000..6e01d624e5
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/metamodel/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains implementations of {@link cipm.consistency.fluentapi.test.metamodel}
+ * for PCM.
+ */
+package cipm.consistency.fluentapi.pcm.test.metamodel;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/package-info.java
new file mode 100644
index 0000000000..ed6de6d7ec
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi.pcm/src/cipm/consistency/fluentapi/pcm/test/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains tests for the generated fluent api for PCM.
+ */
+package cipm.consistency.fluentapi.pcm.test;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.classpath b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.classpath
new file mode 100644
index 0000000000..4a00becd81
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.project b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.project
new file mode 100644
index 0000000000..d0335b2fdd
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.project
@@ -0,0 +1,28 @@
+
+
+ cipm.consistency.fluentapi
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.settings/org.eclipse.jdt.core.prefs b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..c9545f06a4
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/META-INF/MANIFEST.MF b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..85848c01cf
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/META-INF/MANIFEST.MF
@@ -0,0 +1,29 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: cipm.consistency.fluentapi;singleton:=true
+Bundle-Version: 0.2.0.qualifier
+Bundle-ClassPath: .
+Bundle-Vendor: %providerName
+Automatic-Module-Name: cipm.consistency.fluentapi
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Export-Package: cipm.consistency.fluentapi.builder,
+ cipm.consistency.fluentapi.extensions,
+ cipm.consistency.fluentapi.gen,
+ cipm.consistency.fluentapi.gen.init,
+ cipm.consistency.fluentapi.gen.rootapi,
+ cipm.consistency.fluentapi.gen.superinit,
+ cipm.consistency.fluentapi.metamodel,
+ cipm.consistency.fluentapi.postprocessor,
+ cipm.consistency.fluentapi.test,
+ cipm.consistency.fluentapi.test.metamodel
+Require-Bundle: junit-jupiter-api,
+ junit-jupiter-engine,
+ junit-jupiter-params,
+ org.apache.log4j,
+ org.eclipse.emf.codegen.ecore,
+ org.eclipse.core.runtime,
+ org.eclipse.emf.ecore;visibility:=reexport,
+ org.eclipse.emf.ecore.xmi;visibility:=reexport,
+ org.apache.commons.lang
+Bundle-ActivationPolicy: lazy
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/README.md b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/README.md
new file mode 100644
index 0000000000..5b228ce383
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/README.md
@@ -0,0 +1,65 @@
+# Fluent API
+
+This is the base plug-in of the fluent API generation, which contains the elements that the generation of fluent APIs for individual (EMF-based) metamodels require. The elements within this plug-in are mostly metamodel agnostic and must be extended with the means to access and work with concrete metamodels. It is intended to have one fluent API plug-in per concrete metamodel (or a sub-metamodel thereof).
+
+This plug-in considers the same setup as the [CIPM repository](../../../README.md).
+
+## Introduction
+
+The purpose of the fluent API is to facilitate building models from their (EMF-based) metamodels. To this end, the fluent API offers methods that use dynamic EMF under the hood, in order to instantiate model elements and modify their features. In doing so, fluent api hides the complication of dynamic EMF from outside and provides simpler to understand methods. In a sense, the fluent API implements an advanced builder pattern for building models.
+
+The core concept of the fluent API is to make dynamic model building more practical via chainable method calls, bookmarking (marking) certain model elements and deferring some model building steps till certain model elements are marked. The latter enables maintaining the flow of the model building in the face of dependencies between model elements, which require certain model elements to exist before others.
+
+Exemplary usage of the fluent API are present under test packages within the plug-ins of the fluent API generation implementations of individual metamodels.
+
+## Plug-in Structure
+
+This plug-in, as well as those of the extending plug-ins, have a package-based structure with the base package having the same name as the plug-in `cipm.consistency.fluentapi.`, where `` should be replaced with the name of the concrete metamodel, or be left out for the base plug-in.
+
+The fluent api generation code is inside the packages within the [src](./src) directory:
+
+- `cipm.consistency.fluentapi..builder`: Contains the test class that generates the fluent api model
+- `cipm.consistency.fluentapi..extensions`: Contains some static classes with functions that the generated fluent api code uses (extension classes)
+- `cipm.consistency.fluentapi..gen.*`: Contains the logic to generate the fluent api model. Currently only present in the base plug-in.
+- `cipm.consistency.fluentapi..metamodel`: Contains the means to access and work with concrete (EMF-based) metamodels
+- `cipm.consistency.fluentapi..postprocessor`: Contains classes that can be used to post-process the generated fluent api model, which adjust the generated fluent api model after its generation
+- `cipm.consistency.fluentapi..test`: Contains tests for the extension classes and/or the generated fluent api code. This is an optional package and can be removed.
+- `cipm.consistency.fluentapi..test.metamodel`: Contains tests that analyse the generated fluent api model code regarding its generated elements (such as the methods). This is an optional package and can be removed.
+
+The fluent api code will be generated within the [src-gen](./src-gen) directory, following the typical EMF code generation scheme. In most cases, only the `cipm.consistency.fluentapi..api` package is relevant from outside. It contains the fluent api class `FluentAPI`, which is the class that should be used as a facade of the fluent api.
+
+## Fluent API Generation
+
+Under normal circumstances, the following steps should generate the fluent api code in Eclipse IDE:
+
+1) Navigate to the `"cipm.consistency.fluentapi..builder"` package, where `` should be replaced with the name of the concrete metamodel
+2) Run the test case in the builder test class (currently called `FluentAPIBuilder`), which inherits the template test case from the `cipm.consistency.fluentapi.builder.FluentAPIAbstractBuilder` class using Eclipse IDE: "Run As > JUnit Plug-in Test"
+3) Navigate to the `cipm.consistency.fluentapi..builder/metamodel` folder
+4) Open the `.genmodel` file (currently named `-fluentapi.genmodel`) and generate the fluent api model using Eclipse IDE: "Right Click on the only node > Generate Model Code". The fluent api files should be generated under the `src-gen` folder
+5) (Optional) Refresh and clean the plug-in, then run the tests therein (excluding the test class from 2) )
+
+## Implementing Fluent API for Further Metamodels
+
+Under normal circumstances, the following steps should suffice to implement the fluent API generation for an individual metamodel:
+
+1) Create a new plug-in `"cipm.consistency.fluentapi..builder"` package, where `` should be replaced with the name of the concrete metamodel
+2) Add `"cipm.consistency.fluentapi"` as a required bundle, as well as other plug-ins that are needed for the concrete metamodel
+3) Extend the classes `cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter` and `cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelProvider` accordingly
+4) Extend the test class `cipm.consistency.fluentapi.builder.FluentAPIAbstractBuilder` accordingly
+
+If certain fluent API methods should be generated specifically for the concrete metamodel (such as convenience methods), consider implementing post-processors and using them in the test class from 4).
+
+## Limitations
+
+The current implementation of the fluent API has the following (non-exhaustive) list of limitations:
+
+- Fluent API generation is implemented in Java 11, which may or may not conform later Java versions
+ - The generated fluent api code also conforms Java 11
+
+- Names of the metamodel elements have to be unique within the metamodel; i.e. having 2 metamodel elements "namespace1.elementName" and "namespace2.elementName" is not foreseen, only one metamodel element with the name "elementName" may exist
+ - Not abiding this may cause issues with the fluent api model generation, which requires explicit handling
+
+- No generic type support in metamodels, i.e. fluent api will not account for type parameters in metamodel elements, such as the "T" in `"Class"`
+
+- No (explicit) support for metamodel constraints and invariants (such as OCL constraints)
+ - All constraints have to be explicitly addressed in the fluent api model generation for individual metamodels
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/build.properties b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/build.properties
new file mode 100644
index 0000000000..c4bc00d14e
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/build.properties
@@ -0,0 +1,7 @@
+#
+
+bin.includes = .,\
+ META-INF/
+jars.compile.order = .
+source.. = src/
+output.. = bin/
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/builder/FluentAPIAbstractBuilder.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/builder/FluentAPIAbstractBuilder.java
new file mode 100644
index 0000000000..db114eff59
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/builder/FluentAPIAbstractBuilder.java
@@ -0,0 +1,246 @@
+package cipm.consistency.fluentapi.builder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenJDKLevel;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.osgi.framework.FrameworkUtil;
+
+import cipm.consistency.fluentapi.gen.FluentAPIGenerationContext;
+import cipm.consistency.fluentapi.gen.ModelConstants;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelFilter;
+import cipm.consistency.fluentapi.metamodel.FluentAPITargetMetamodelPackageProvider;
+
+/**
+ * Encapsulates the means to generate a fluent api model for a metamodel, i.e.
+ * the ".ecore" and ".genmodel" files of the fluent api model. To keep the
+ * fluent api generation as metamodel agnostic as possible, integration of the
+ * specific metamodel is achieved via abstract methods.
+ *
+ * The generation of the fluent api model is encapsulated within the
+ * {@link #generateModelFiles()} test case.
+ *
+ * @author Alp Torac Genc
+ */
+public abstract class FluentAPIAbstractBuilder {
+ /**
+ * The (default) suffix all generated fluent api model files (i.e. the ecore and
+ * genmodel files) should have
+ */
+ private static final String commonModelSuffix = "fluentapi";
+ /**
+ * The (default) name of the directory, where the fluent api model files will be
+ * generated
+ */
+ private static final String commonModelDirName = "metamodel";
+ /**
+ * The (default) name of the ecore file associated with the fluent api
+ */
+ private static final String commonEcoreModelFileName = commonModelSuffix + ".ecore";
+ /**
+ * The (default) name of the genmodel file associated with the fluent api
+ */
+ private static final String commonGenModelFileName = commonModelSuffix + ".genmodel";
+ /**
+ * The (default) name of the directory, where the fluent api itself will be
+ * generated (i.e. the classes that can be used to construct models of the
+ * targeted metamodel)
+ */
+ private static final String modelGenerationTargetDirName = "src-gen";
+
+ /**
+ * Generates the fluent API model files (i.e. the ecore and genmodel files).
+ *
+ * Can be overridden in concrete implementors to change how the model files are
+ * generated. If overridden, the overriding method should have the {@code @Test}
+ * annotation for JUnit to detect it as a test case. Otherwise, the overriding
+ * method will not be recognized as a test method and no model files will be
+ * generated.
+ */
+ @Test
+ public void generateModelFiles() {
+ cleanPreviousModelFiles();
+
+ var context = new FluentAPIGenerationContext();
+ context.setTargetMetamodelPackageProvider(getTargetMetamodelPackageProvider());
+ context.setTargetMetamodelFilter(getTargetMetamodelFilter());
+ context.setBasePackageName(
+ ModelConstants.BASE_PACKAGE_NAME.getFor(getTargetMetamodelPackageProvider().getTargetMetamodelName()));
+
+ var modelResSet = new ResourceSetImpl();
+ var ecoreRes = modelResSet.createResource(URI.createFileURI(getEcoreModelFilePath().toString()));
+ var genModelRes = modelResSet.createResource(URI.createFileURI(getGenModelFilePath().toString()));
+
+ generateEcoreModel(ecoreRes, context);
+ generateGenModel(genModelRes, ecoreRes, context);
+
+ try {
+ ecoreRes.save(null);
+ genModelRes.save(null);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Assertions.fail(e);
+ }
+ }
+
+ /**
+ * @return The value of the "model name" property of the genmodel of the fluent
+ * api.
+ */
+ protected String getModelName() {
+ return getTargetMetamodelPackageProvider().getTargetMetamodelName() + "-" + commonModelSuffix;
+ }
+
+ /**
+ * @return The absolute path to the .genmodel file associated with the fluent
+ * API model
+ */
+ protected Path getGenModelFilePath() {
+ return new File(getModelFilesDirName()).getAbsoluteFile().toPath().resolve(getGenModelFileName());
+ }
+
+ /**
+ * @return The name of the ".genmodel" file associated with the fluent API model
+ */
+ protected String getGenModelFileName() {
+ return getTargetMetamodelPackageProvider().getTargetMetamodelName() + "-" + commonGenModelFileName;
+ }
+
+ /**
+ * @return The name of the directory (only the name of the inner-most directory,
+ * not the path to it), where the .ecore and .genmodel file will be
+ * saved.
+ */
+ protected String getModelFilesDirName() {
+ return commonModelDirName;
+ }
+
+ /**
+ * @return The name of the ecore file (only the name of the ecore file, not the
+ * path to it)
+ */
+ protected String getEcoreModelFileName() {
+ return getTargetMetamodelPackageProvider().getTargetMetamodelName() + "-" + commonEcoreModelFileName;
+ }
+
+ /**
+ * @return The absolute path to the directory, where the model files ("ecore"
+ * and "genmodel" files) fill be saved.
+ */
+ protected Path getModelFilesPath() {
+ return new File(getModelFilesDirName()).getAbsoluteFile().toPath();
+ }
+
+ /**
+ * @return The absolute path to the ecore model file associated with the fluent
+ * api
+ */
+ protected Path getEcoreModelFilePath() {
+ return getModelFilesPath().resolve(getEcoreModelFileName());
+ }
+
+ /**
+ * Cleans up the potential previously created model files for this builder
+ * instance.
+ */
+ protected void cleanPreviousModelFiles() {
+ var fluentAPIModelFilesDir = getModelFilesPath().toFile();
+ if (fluentAPIModelFilesDir.exists() && fluentAPIModelFilesDir.listFiles() != null) {
+ for (var file : fluentAPIModelFilesDir.listFiles()) {
+ file.delete();
+ }
+ fluentAPIModelFilesDir.delete();
+ }
+ }
+
+ /**
+ * @return The value of the "compliance level" property of the genmodel of
+ * fluent api.
+ */
+ protected static GenJDKLevel getJDKVersion() {
+ var runtimeVer = Runtime.version().version().get(0);
+ GenJDKLevel lvl = null;
+ for (var ver : GenJDKLevel.values()) {
+ if (ver.getLiteral().startsWith(String.valueOf(runtimeVer.doubleValue()))) {
+ lvl = ver;
+ break;
+ }
+ }
+ return lvl;
+ }
+
+ /**
+ * @return The value of the "model plugin ID" property of the genmodel of fluent
+ * api.
+ */
+ protected String getModelPluginID() {
+ return ModelConstants.BASE_PACKAGE_NAME.getFor(getTargetMetamodelPackageProvider().getTargetMetamodelName());
+ }
+
+ /**
+ * Returns The path, at which the fluent API will be generated.
+ *
+ * Can be overridden in concrete implementors.
+ *
+ * @return The value of the "model directory" property of the genmodel of fluent
+ * api as Path.
+ */
+ protected Path getGeneratedFluentAPIModelDirectoryPath() {
+ return Path.of(getCurrentPluginName(), modelGenerationTargetDirName);
+ }
+
+ /**
+ * Meant to be used by {@link #getGeneratedFluentAPIModelDirectoryPath()}.
+ *
+ * @return The name of the current plug-in.
+ */
+ private String getCurrentPluginName() {
+ var bundle = FrameworkUtil.getBundle(getClass());
+ var name = bundle.getSymbolicName();
+ return name;
+ }
+
+ /**
+ * @return The object that grants access to the metamodel, for which the fluent
+ * api should be generated.
+ */
+ protected abstract FluentAPITargetMetamodelPackageProvider getTargetMetamodelPackageProvider();
+
+ /**
+ * @return The object that is used to filter the elements of the metamodel.
+ */
+ protected abstract FluentAPITargetMetamodelFilter getTargetMetamodelFilter();
+
+ /**
+ * Generates the {@link GenModel} instance of the fluent api model from the
+ * previously generated Ecore model
+ * ({@link #generateEcoreModel(Resource, FluentAPIGenerationContext)}). The
+ * return value allows access to the {@link GenModel} instance in the rest of
+ * the fluent api generation, in order to allow further modifications to it.
+ *
+ * @param genModelRes The Resource instance, in which the {@link GenModel}
+ * instance will be created
+ * @param ecoreRes The Resource instance of the fluent api model
+ * @param context The object that encapsulates the context of the fluent api
+ * generation
+ * @return The {@link GenModel} instance of the fluent api model
+ */
+ protected abstract GenModel generateGenModel(Resource genModelRes, Resource ecoreRes,
+ FluentAPIGenerationContext context);
+
+ /**
+ * Generates the fluent api model (as Ecore model).
+ *
+ * @param ecoreRes The Resource instance of the fluent api model
+ * @param context The object that encapsulates the context of the fluent api
+ * generation
+ */
+ protected abstract void generateEcoreModel(Resource ecoreRes, FluentAPIGenerationContext context);
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/builder/package-info.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/builder/package-info.java
new file mode 100644
index 0000000000..e2a1a16f20
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/builder/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains the (abstract) builder class, which is responsible for building the
+ * fluent api model that consists of an ecore and a genmodel file.
+ */
+package cipm.consistency.fluentapi.builder;
\ No newline at end of file
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/extensions/FluentAPIInitialisationStorage.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/extensions/FluentAPIInitialisationStorage.java
new file mode 100644
index 0000000000..9d1bd8bf10
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/extensions/FluentAPIInitialisationStorage.java
@@ -0,0 +1,69 @@
+package cipm.consistency.fluentapi.extensions;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * The extension class of fluent api that stores Initialisation instances that
+ * are created within the fluent api and are actively being used to create model
+ * elements. Since the fluent api model is EMF-based, implementing static
+ * attributes in its EClasses is challenging. Making the attribute containing
+ * initialisation instances static is important, since all fluent api instances
+ * should have access to all ongoing initialisation instances (i.e.
+ * initialisation instances that are actively being used), hence the
+ * initialisation storing logic is moved to this class. This class does not
+ * allow duplicated Initialisation instances.
+ *
+ *
+ * The methods within this class are meant for Initialisation instances,
+ * although they take parameters of type EObject. This is due to the fact that
+ * fluent api model is generated dynamically (hence the Initialisation classes
+ * are not guaranteed to exist at this time).
+ *
+ *
+ * Note: Changing any public member within this file (i.e. either this class or
+ * its methods) requires adapting the generation of fluent api. This is due to
+ * Java limitations, which do not allow dynamically adjusting static elements,
+ * such as method or class names.
+ *
+ * @author Alp Torac Genc
+ */
+public final class FluentAPIInitialisationStorage {
+ private static final Collection ongoingInits = new LinkedHashSet<>();
+
+ /**
+ * @return An unmodifiable list of all ongoing initialisations.
+ */
+ public static List getOngoingInitialisations() {
+ return List.copyOf(ongoingInits);
+ }
+
+ /**
+ * Removes the given Initialisation instance from this class
+ *
+ * @param init A given Initialisation instance, potentially stored in this class
+ */
+ public static void dropOngoingInitialisation(EObject init) {
+ ongoingInits.remove(init);
+ }
+
+ /**
+ * Adds the given Initialisation instance to this class. Does nothing if init
+ * has already been added previously.
+ *
+ * @param init A given Initialisation instance
+ */
+ public static void addOngoingInitialisation(EObject init) {
+ ongoingInits.add(init);
+ }
+
+ /**
+ * Removes all stored Initialisation instances from this class
+ */
+ public static void clearAllOngoingInitialisations() {
+ ongoingInits.clear();
+ }
+}
diff --git a/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/extensions/FluentAPIMarkExtension.java b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/extensions/FluentAPIMarkExtension.java
new file mode 100644
index 0000000000..d425b01c37
--- /dev/null
+++ b/commit-based-cipm/fluentapi/cipm.consistency.fluentapi/src/cipm/consistency/fluentapi/extensions/FluentAPIMarkExtension.java
@@ -0,0 +1,130 @@
+package cipm.consistency.fluentapi.extensions;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * The extension class of fluent api that manages marks in form of (markKey,
+ * markValue) pairs, where markKey is the object that was used to mark the model
+ * element (markValue) via fluent api.
+ *
+ *
+ * Currently, marks are stored in a Map, meaning that a markKey may only be used
+ * to mark a single markValue. Using the same markKey to mark another model
+ * element markValue2 will override (markKey, markValue) to (markKey,
+ * markValue2). However, markValue can be marked with multiple markKeys.
+ *
+ *
+ * Note: Changing any public member within this file (i.e. either this class or
+ * its methods) requires adapting the generation of fluent api. This is due to
+ * Java limitations, which do not allow dynamically adjusting static elements,
+ * such as method or class names.
+ *
+ * @author Alp Torac Genc
+ * @see {@link FluentAPIWaitForMarkExtension}
+ */
+public class FluentAPIMarkExtension {
+ /**
+ * The map that contains marks in form of (markKey, markVal) pairs.
+ */
+ private static final Map