Giter Club home page Giter Club logo

epsilon-runtime's Introduction

epsilon-runtime

badge

Eclipse Epsilon Runtime for Maven and OSGi. There are builders and helper classes, URI handlers that can help the usage of Epsilon out of Eclipse ecosystem.

What is Epsilon?

Epsilon is a family of languages and tools for code generation, model-to-model transformation, model validation, comparison, migration and refactoring that work out of the box with EMF, UML, Simulink, XML and other types of models.

The currently supported epsilon language dialects are:

  • EOL (Epsilon Object Language)

  • ETL (Epsilon Transformation Language)

  • EVL (Epsilon Validation Language)

  • EGL (Epsilon Generation Language)

  • EGX (Epsilon Generation XML(?))

  • EML (Epsilon Merging Language)

  • ECL (Epsilon Comparison Language)

To understand the epsilon stack recommended to read the free epsilon book: https://www.eclipse.org/epsilon/doc/book/

Example

This example there is a model definition which can define a simple class structure with attributes and references. That models can be transformed to Liquibase (https://www.liquibase.org/) scripts. Liquibase XML format used which is defined with an XSD file, which techcally the meta model of an XML file. The original XSD file was modified (https://github.com/BlackBeltTechnology/epsilon-runtime/blob/develop/epsilon-runtime-execution/src/test/resources/liquibase.xsd) to be compatible with Ecore metamodel structure, so the output of transformation will be an XML file which is a Liquibase XML itself.

1. Define a meta-model. The meta-model contains the definition of our structure:

<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="data" nsURI="http://www.blackbelt.hu/epsilon-runtime/test" nsPrefix="data">
  <eClassifiers xsi:type="ecore:EClass" name="DataModel">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="entity" upperBound="-1"
        eType="#//Entity" containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Entity">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="attribute" lowerBound="1"
        upperBound="-1" eType="#//Attribute" containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="reference" upperBound="-1"
        eType="#//EntityReference" containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Attribute">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="EntityReference">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="toMany" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="target" lowerBound="1"
        eType="#//Entity"/>
  </eClassifiers>
</ecore:EPackage>
Note

In EMF (Emfatic fomat) - You can convert between .ecore and .emf within eclipse. The epsilon-runtime will support emfatic format directly soon.

@namespace(uri="http://www.blackbelt.hu/epsilon-runtime/test", prefix="data")
package data;

class DataModel {
  attr String name;
  val Entity[*] entity;
}

class Entity { // (1)
  attr String name;
  val Attribute[+] attribute;
  val EntityReference[*] reference;
}

class Attribute { // (2)
  attr String name;
  attr String type;
}

class EntityReference { // (3)
  attr String name;
  attr boolean toMany;
  ref Entity[1] target;
}
  1. Entity - Represents a class

  2. Attribute - Represents an attribute of class

  3. Reference - Represents a reference to a class

2. Define the model based on meta-model

<?xml version="1.0" encoding="ASCII"?>
<data:DataModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:data="http://www.blackbelt.hu/epsilon-runtime/test" xmi:id="_CeiO8EAJEemOdvXw1zCXyw">
  <entity xmi:id="_Ds1OEEAJEemOdvXw1zCXyw" name="Test1">
    <attribute xmi:id="_FB4VcEAJEemOdvXw1zCXyw" name="attr1" type="String"/>
  </entity>
  <entity xmi:id="_H8fscEAJEemOdvXw1zCXyw" name="Test2">
    <attribute xmi:id="_Ja6yQEAJEemOdvXw1zCXyw" name="attr2" type="String"/>
    <reference xmi:id="_LwhXsEAJEemOdvXw1zCXyw" name="test1" target="_Ds1OEEAJEemOdvXw1zCXyw"/>
  </entity>
</data:DataModel>
Note

In HUTN (Emfatic fomat) - You can convert between .model and .hutn within eclipse. The epsilon-runtime will support hutn format directly soon.

@Spec {
	metamodel "http://www.blackbelt.hu/epsilon-runtime/test" {
		nsUri: "http://www.blackbelt.hu/epsilon-runtime/test"
	}
}

package  {
	DataModel "DataModel1" {
		entity:
			Entity "Test1" {
				name: "Test1"
				attribute:
					Attribute "attr1" {
						name: "attr1"
						type: "String"
					}

			Entity "Test2" {
				name: "Test2"
				attribute:
					Attribute "attr2" {
						name: "attr2"
						type: "String"
					}
				reference:
					EntityReference "test1" {
						name: "test1"
						target: Entity "Test1"
					}
			}
	}
}

3. Define the transformation rules

The rules can be defined in ETL language (Epsilon Transformation Language).

rule DataModelToChangeLog
	transform s : TEST1!DataModel
	to t : LIQUIBASE!databaseChangeLog {
}

rule DataModelToChangeSet
	transform s : TEST1!DataModel
	to t : LIQUIBASE!ChangeSet {
	    t.id =  s.name;
	    t.author = "test1toliquibase";
		s.equivalent("DataModelToChangeLog").changeSet.add(t);
}

rule EntityToCreateTable
	transform s : TEST1!Entity
	to t : LIQUIBASE!CreateTable {
		t.tableName = s.name;
		TEST1!DataModel.all.selectOne(e | e.entity.contains(s)).equivalent("DataModelToChangeSet").createTable.add(t);
}

rule EntityToIdColumn
	transform s : TEST1!Entity
	to t : LIQUIBASE!Column {
		t.name = "ID";
		t.type = "Identifier";
		s.equivalent("EntityToCreateTable").column.add(t);
}

rule EntityToPrimaryKey
	transform s : TEST1!Entity
	to t : LIQUIBASE!AddPrimaryKey {
		t.tableName = s.name;
		t.columnNames = "ID";
		TEST1!DataModel.all.selectOne(d | d.entity.contains(s)).equivalent("DataModelToChangeSet").addPrimaryKey.add(t);
}

rule AttributeToColumn
	transform s : TEST1!Attribute
	to t : LIQUIBASE!Column {
		t.name = s.name;
		t.type = s.type;
		TEST1!Entity.all.selectOne(e | e.attribute.contains(s)).equivalent("EntityToCreateTable").column.add(t);
}

rule EntityReferenceToColumn
	transform s : TEST1!EntityReference
	to t : LIQUIBASE!Column {
		t.name = "ID_" + s.name;
		t.type = "Identifier";
		TEST1!Entity.all.selectOne(e | e.reference.contains(s)).equivalent("EntityToCreateTable").column.add(t);
}

rule EntityReferenceToAddForeignKeyConstraint
	transform s : TEST1!EntityReference
	to t : LIQUIBASE!AddForeignKeyConstraint {
		var entity : TEST1!Entity = TEST1!Entity.all.selectOne(e | e.reference.contains(s));
		t.constraintName = "FK_" + entity.name + "_" + s.`target`.name;

		t.baseTableName = entity.name;
		t.baseColumnNames = "ID_" + s.`target`.name;

		t.referencedColumnNames = "ID";
		t.referencedTableName = s.`target`.name;

		TEST1!DataModel.all.selectOne(e | e.entity.contains(entity)).equivalent("DataModelToChangeSet").addForeignKeyConstraint.add(t);
}

4. Run the transformation

        // Preparing URI handler
        uriHandler = new NioFilesystemnRelativePathURIHandlerImpl("urn", FileSystems.getDefault(),
                new File(targetDir(), "test-classes").getAbsolutePath());

        // Setup resourcehandler used to load metamodels
        executionResourceSet = new CachedResourceSet();
        executionResourceSet.getURIConverter().getURIHandlers().add(0, uriHandler);

        // Executrion context
        ExecutionContext executionContext = executionContextBuilder()
                .log(slf4jLogger)
                .resourceSet(executionResourceSet)
                .metaModels(ImmutableList.of(
                        "urn:epsilon-runtime-test.ecore"))
                .modelContexts(ImmutableList.of(
                        emfModelContextBuilder()
                                .log(slf4jLogger)
                                .name("TEST1")
                                .emf("urn:epsilon-runtime-test1.model")
                                .build(),

                        xmlModelContextBuilder()
                                .log(slf4jLogger)
                                .name("LIQUIBASE")
                                // TODO: XSDEcoreBuilder creating separate ResourceSet, so URIHandlers are not
                                // working. Have to find a way to inject
                                // .xsd("urn:liquibase.xsd")
                                .xsd(new File(targetDir(), "test-classes/liquibase.xsd").getAbsolutePath())
                                .xml("urn:epsilon-transformedliquibase.xml")
                                .readOnLoad(false)
                                .storeOnDisposal(true)
                                .build()))
                .sourceDirectory(scriptDir())
                .build();

        // run the loading
        executionContext.load();

        // Transformation script
        executionContext.executeProgram(
                etlExecutionContextBuilder()
                        .source("transformTest1ToLiquibase.etl")
                        .build());

        executionContext.commit();
        executionContext.close();

The output liquibase model is:

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog">
  <changeSet author="test1toliquibase">
    <createTable tableName="Test1">
      <column name="ID" type="Identifier"/>
      <column name="attr1" type="String"/>
    </createTable>
    <createTable tableName="Test2">
      <column name="ID" type="Identifier"/>
      <column name="attr2" type="String"/>
      <column name="ID_test1" type="Identifier"/>
    </createTable>
    <addForeignKeyConstraint baseColumnNames="ID_Test1" baseTableName="Test2" constraintName="FK_Test2_Test1"
        referencedColumnNames="ID" referencedTableName="Test1"/>
    <addPrimaryKey columnNames="ID" tableName="Test1"/>
    <addPrimaryKey columnNames="ID" tableName="Test2"/>
  </changeSet>
</databaseChangeLog>

Contributing to the project

Everyone is welcome to contribute to epsilon-runtime! As a starter, please read the corresponding CONTRIBUTING guide for details!

License

This project is licensed under the Apache License 2.0.

epsilon-runtime's People

Contributors

robertcsakany avatar blackbelt-oss avatar borcsokj avatar dependabot[bot] avatar dependabot-preview[bot] avatar gaborflorian avatar fruska avatar bencegelei avatar kristofkakuszi avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar James Cloos avatar Tibor Botos avatar attila kocsis avatar Gábor Privitzky avatar Szőcs Hunor avatar  avatar  avatar Levente Laszlo avatar buildkite-agent avatar  avatar

Forkers

vorachet

epsilon-runtime's Issues

JNG-18 ⁃ verify EVL rules

Add extension verifying EVLs (expected errors and warnings are checked). Status of EVL scripts will be OK if:

  • no error found (no expected error/warning list is set)
  • error and warning sets are matching expected values

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.