Skip to content

Latest commit

 

History

History
595 lines (484 loc) · 18.7 KB

judo-tatami-jsl-workflow-maven-plugin.adoc

File metadata and controls

595 lines (484 loc) · 18.7 KB

Tatami JSL Workflow maven plugin

This plugin manages and executes generators for JUDO JSL Application codes.

It generates persitence DAO’s and Guice Injector based bootstrap.

Requirements

  • Maven 3.6 and Java 11

Installation

Include the plugin as a dependency in your Maven project. Change LATEST_VERSION to the latest tagged version.

Generating application with minimal settings.

<plugin>
    <groupId>hu.blackbelt.judo.tatami</groupId>
    <artifactId>judo-tatami-jsl-workflow-maven-plugin</artifactId>
    <version>LATEST_VERSION</version>
    <executions>
        <execution>
            <id>generate-application-from-jsl</id>
            <goals>
                <goal>default-model-workflow</goal>
            </goals>
            <phase>generate-sources</phase>
        </execution>
    </executions>
</plugin>
<!-- ... -->

Generation pipeline

The plugin executes model conversion pipeline started with the .jsl defined models. The different models represents different architectual models, which used by the coresponding architectual element.

Model pipeline for .jsl

@startuml
JslDsl -> JSL: JslParser
JSL -> PSM: Jsl2Psm
PSM -> ASM: Psm2Asm
PSM -> Measure: Psm2Measure
ASM -> RDBMS: Asm2Rdbms (hsqldb, postgresql)
PSM -> SDK: Psm2Sdk (hsqldb, postgresql)
RDBMS -> Liquibase: Rdbms2Liquibase (hsqldb, postgresql)

@enduml
  • JslDsl - The JUDO Specification Language model. The source code of the model.

  • JSL - The XMI representation of JslDsl.

  • PSM - Platform Specific Model. It is the formal JUDO definition of platform domain in XMI format.

  • ASM - Artchitecture Specific Model. It is Ecore metamodel based XMI representation of PSM. This model and it’s derivative models are used by the platform.

  • Measure - Special measure model, which helps the correct measurement handling.

  • RDBMS - Relation Data Model in XMI form. It is generated dialect dependent form.

  • Liquibase - This model contains RDBMS model definition for DDL generation. Means it will create the RDBMS schema in a database for the defined ASM model.

Plugin parameters

<execution>
    <id>execute-jsl-transformation</id>
    <phase>compile</phase>
    <goals>
        <goal>default-workflow</goal>
    </goals>
    <configuration>
        <sources>${project.basedir}/src/main/resources/model</sources> <!--(1)-->
        <destination>${project.basedir}/target/generated-sources/model</destination> <!--(2)-->
        <modelNames/> <!--(3)-->
        <modelVersion>${project.version}</modelVersion> <!--(4)-->

        <useDependencies>false</useDependencies> <!--(5)-->

        <dialects>hsqldb,postgresql</dialects> <!--(6)-->

        <ignoreJsl2Psm>false</ignorePsm2Asm> <!--(7)-->
        <ignoreJsl2Ui>false</ignorePsm2Asm> <!--(8)-->
        <ignorePsm2Asm>false</ignorePsm2Asm> <!--(9)-->
        <ignorePsm2AsmTrace>false</ignorePsm2AsmTrace> <!--(10)-->
        <ignorePsm2Measure>false</ignorePsm2Measure> <!--(11)-->
        <ignorePsm2MeasureTrace>false</ignorePsm2MeasureTrace> <!--(12)-->
        <ignoreAsm2Rdbms>false</ignoreAsm2Rdbms> <!--(13)-->
        <ignoreAsm2RdbmsTrace>false</ignoreAsm2RdbmsTrace> <!--(14)-->
        <ignoreRdbms2Liquibase>false</ignoreRdbms2Liquibase> <!--(15)-->
        <ignoreAsm2Expression>false</ignoreAsm2Expression> <!--(16)-->
        <useCache>false</useCache> <!--(17)-->
        <runInParallel>true</runInParallel> <!--(18)-->
        <saveModels>true</saveModels> <!--(19)-->
        <enableMetrics>true</enableMetrics> <!--(20)-->
        <validateModels>false</validateModels> <!--(21)-->
        <rdbmsCreateSimpleName>false</rdbmsCreateSimpleName> <!--(22)-->
        <rdbmsNameSize>-1</rdbmsNameSize> <!--(23)-->
        <rdbmsShortNameSize>-1</rdbmsShortNameSize> <!--(24)-->
        <rdbmsTablePrefix>T_</rdbmsTablePrefix> <!--(25)-->
        <rdbmsColumnPrefix>C_</rdbmsColumnPrefix> <!--(26)-->
        <rdbmsForeignKeyPrefix>FK_</rdbmsForeignKeyPrefix> <!--(27)-->
        <rdbmsInverseForeignKeyPrefix>FK_INV_</rdbmsInverseForeignKeyPrefix> <!--(28)-->
        <rdbmsJunctionTablePrefix>J_</rdbmsJunctionTablePrefix> <!--(29)-->
        <rdbmsTableNameMaxSize>-1</rdbmsTableNameMaxSize> <!--(30)-->
        <rdbmsColumnNameMaxSize>-1</rdbmsColumnNameMaxSize> <!--(31)-->
        <ignoreAsm2Keycloak>true</ignoreAsm2Rdbms> <!--(32)-->
        <ignoreAsm2KeycloakTrace>true</ignoreAsm2RdbmsTrace> <!--(33)-->
    </configuration>
</execution>

URI type parameters can be file or mvn with the following coordinate: mvn:<groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>[!path/in/archive]

  1. (Optional) Sources URI. It is a coma separated list. When one or more models are defined, added them, when a directory in a filesystem or artifact is defined scans recursively for .jsl files.

    (Default: src/main/resources/model directory inside the project)

  2. (Optional) Destination path where the transformation output is generated. It contains intermediate models, traces and source code.

    Important
    When the source codes have to be compiled, use the build-helper-plugin to add source folder, or have to enable compileSdk and createSdkJar option.

    (Default: ${project.basedir}/target/generated-sources/model)

  3. (Optional) Logical model names. When multiple jsl files are defined, by default all of them are compiled. Most of the time only one or more dedicated model can be compiled with the list of the names. (the name which is dfined as model in the first line of .jsl)

    (Default: <none>)

  4. (Optional) Which version number stored in the generated models.

    (Default: ${project.version})

  5. (Optional) Use maven dependencies as source of JSL files. When it is true, scans all dependencies transitively for .jsl files. When you have .jsl files packaged and stored in maven, add to your pom.xml.

    (Default: false)

  6. (Optional) Coma separated list of dialects generated. Valid values are:

    • hsqldb,

    • postgresql

      (Default: hsqldb,postgresql)

  7. (Optional) Ignore Jsl2Psm work.

    Default: false

  8. (Optional) Ignore Jsl2Ui work.

    Default: false

  9. (Optional) Ignore Psm2Asm work.

    Default: false

  10. (Optional) Ignore Psm2Asm Trace.

    Default: true

  11. (Optional) Ignore Psm2Measure work.

    Default: false

  12. (Optional) Ignore Psm2Measure Trace.

    Default: true

  13. (Optional) Ignore Asm2Rdbms work.

    Default: false

  14. (Optional) Ignore Asm2Rdbms Trace.

    Default: false

  15. (Optional) Ignore Rdbms2Liquibase work.

    Default: false

  16. (Optional) Ignore Asm2Expression work.

    Default: false

  17. (Optional) Use cache in model transformations.

    Default: false

  18. (Optional) Run in parallel when possible, parallel execution is used in multicore system

    (Default: true)

  19. (Optional) Save models after execution. After execution the models are stored on destination.

    (Default: false)

  20. (Optional) Enable generation time statistics after execution

    (Default: true)

  21. (Optional) Validate model on load and save

    (Default: false)

  22. Create simple name. (Optional) Using the model name as SQL name. It does not check namespace collosion. (Default: false)

  23. Full size of SQL name without abbreviation algorithm. When -1 is used it uses database specific default.

    (Default: -1)

  24. Short size of SQL name without abbreviation algorithm. This size is used as namespace fragment size. When -1 is used it uses database specific default.

    (Default: -1)

  25. Table prefix used for table names. When - is used no prefix is used.

    (Default: T_)

  26. Column prefix used for column names. When - is used no prefix is used.

    (Default: C_)

  27. Foreign key prefix used for foreign key names. When - is used no prefix is used.

    (Default: FK_)

  28. Inverse Foreign key prefix used for foreign key names. When - is used no prefix is used.

    (Default: FK_INV_)

  29. Junction table prefix used for table names. When - is used no prefix is used.

    (Default: J_)

  30. Maximum table name size of SQL name. This size is used as table name maximum size. When -1 is used it uses database specific default.

    (Default: -1)

  31. Maximum column name size of SQL name. This size is used as column name maximum size. When -1 is used it uses database specific default.

    (Default: -1)

  32. (Optional) Ignore Asm2Keycloak work.

    Default: false

  33. (Optional) Ignore Asm2Keycloak Trace.

    Default: false

Example

  • src/main/model/salesmodel.jsl

    model SalesModel;
    
    type numeric Integer(precision = 9, scale = 0);
    type string String(min-size = 0, max-size = 128);
    type string PhoneNumber(min-size = 0, max-size = 32, regex = "^(\\+\\d{1,2}\\s)?\\(?\\d{3}\\)?[\\s.-]\\d{3}[\\s.-]\\d{4}$");   // escape sequencing does not work in regexp!!!!
    type boolean Boolean;
    
    type date Date;
    type timestamp Timestamp;
    type binary Binary(mime-types = ["text/plain"], max-file-size=1 GB);
    
    error MyError {
    	field Integer code;
    	field String msg = "Internal Server Error";
    }
    
    error MyExtendedError extends MyError {
    	field Integer extra = 0;
    }
    
    enum LeadStatus {
    	OPPORTUNITY = 0;
    	LEAD = 1;
    	PROJECT = 2;
    }
    
    entity abstract Person {
    	field String firstName;
    	field String lastName;
    	relation Lead[] leadsNoOpposite;
    	derived	String fullName => self.firstName + " "
    		+ self.lastName ;
    }
    
    entity SalesPerson extends Person {
    	relation Lead[] leads opposite salesPerson;
    	derived Lead[] leadsOver10 => self.leadsOver(limit = 10);
    	derived Integer numberOfLeads => self.leads!size();
    }
    
    entity Lead {
    	field Integer value = 100000;
    	relation required SalesPerson salesPerson opposite leads;
    	constraint ValueMoreThan10 self.value > 10 onerror MyError(code = 10, msg = "Error message");
    }
    
    entity Customer {
    	identifier required String name;
    	relation Lead lead opposite-add customer;
    }
  • pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>hu.blackbelt.judo.test</groupId>
        <version>1.0.0-SNAPSHOT</version>
        <artifactId>judo-sales-model</artifactId>
        <packaging>jar</packaging>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>11</maven.compiler.source>
            <maven.compiler.target>11</maven.compiler.target>
    
            <judo-runtime-core-version>1.0.0</judo-runtime-core-version>  <!--(1)-->
            <judo-tatami-jsl-version>1.1.0</judo-tatami-jsl-version> <!--(2)-->
        </properties>
        <build>
            <plugins>
                <plugin>
                    <groupId>hu.blackbelt.judo.tatami</groupId>
                    <artifactId>judo-tatami-jsl-workflow-maven-plugin</artifactId>
                    <version>${judo-tatami-jsl-version}</version>
                    <executions>
                        <execution>
                            <id>generate-models</id>
                            <goals>
                                <goal>default-model-workflow</goal>
                            </goals>
                            <phase>generate-sources</phase>
                        </execution>
                    </executions>
                    <configuration>
                        <modelNames>SalesModel</modelNames>
                        <sources>${basedir}/src/main/model</sources>
                        <dialects>hsqldb</dialects>
                    </configuration>
                </plugin>
    
                <!--(3)-->
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>build-helper-maven-plugin</artifactId>
                    <version>3.3.0</version>
                    <executions>
                        <execution>
                            <id>add-source</id>
                            <phase>generate-sources</phase>
                            <goals>
                                <goal>add-source</goal>
                            </goals>
                            <configuration>
                                <sources>
                                    <source>${project.basedir}/target/model/sdk/SalesModel</source>
                                </sources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
    
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.22.2</version>
                        <dependencies>
                            <dependency>
                                <groupId>org.junit.jupiter</groupId>
                                <artifactId>junit-jupiter-engine</artifactId>
                                <version>5.8.2</version>
                            </dependency>
                        </dependencies>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>hu.blackbelt.judo.runtime</groupId>
                    <artifactId>judo-runtime-core-dependencies</artifactId>
                    <version>${judo-runtime-core-version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
    
                <dependency>
                    <groupId>hu.blackbelt.judo.tatami</groupId>
                    <artifactId>judo-tatami-jsl-jsl2psm</artifactId>
                    <version>${judo-tatami-jsl-version}</version>
                </dependency>
    
                <dependency>
                    <groupId>hu.blackbelt.judo.tatami</groupId>
                    <artifactId>judo-tatami-jsl-workflow</artifactId>
                    <version>${judo-tatami-jsl-version}</version>
                </dependency>
    
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
            <dependency>
                <groupId>hu.blackbelt.judo.runtime</groupId>
                <artifactId>judo-runtime-core</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.judo.runtime</groupId>
                <artifactId>judo-runtime-core-guice-hsqldb</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.judo.runtime</groupId>
                <artifactId>judo-runtime-core-guice-postgresql</artifactId>
            </dependency>
    
            <dependency>
                <groupId>javax.validation</groupId>
                <artifactId>validation-api</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.judo</groupId>
                <artifactId>judo-dao-api</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.mapper</groupId>
                <artifactId>mapper-api</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.judo.meta</groupId>
                <artifactId>hu.blackbelt.judo.meta.asm.model</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.judo</groupId>
                <artifactId>judo-dispatcher-api</artifactId>
            </dependency>
    
            <dependency>
                <groupId>hu.blackbelt.judo</groupId>
                <artifactId>judo-sdk-common</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter</artifactId>
                <version>5.8.2</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>5.8.2</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    </project>
    1. Runtime core version required to load end execute transformated model

    2. Tatami JSL version required to transform JSL script

    3. Build helper plugin adds the generated SDK source code to normal maven build pipeline

  • /src/test/java/hu/blackbelt/judo/test/salesmodel/SalesModelTest.java

    package hu.blackbelt.judo.test.salesmodel;
    
    import com.google.inject.Guice;
    import com.google.inject.Inject;
    import com.google.inject.Injector;
    import hu.blackbelt.judo.runtime.core.guice.JudoDefaultModule;
    import hu.blackbelt.judo.runtime.core.guice.JudoModelHolder;
    import hu.blackbelt.judo.runtime.core.guice.dao.rdbms.hsqldb.JudoHsqldbModules;
    import hu.blackbelt.judo.runtime.core.dao.rdbms.hsqldb.HsqldbDialect;
    import hu.blackbelt.judo.test.salesmodel.daoprovider.salesmodel.SalesModelDaoModules;
    import hu.blackbelt.judo.test.salesmodel.sdk.salesmodel.salesmodel.Person;
    import hu.blackbelt.judo.test.salesmodel.sdk.salesmodel.salesmodel.SalesPerson;
    import hu.blackbelt.judo.sdk.query.StringFilter;
    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    import java.io.File;
    import java.util.List;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    @Slf4j
    class SalesModelTest {
    
        Injector injector; // (1)
    
        @Inject
        SalesPerson.SalesPersonDao salesPersonDao; // (2)
    
        @Inject
        Person.PersonDao personDao; // (3)
    
        @BeforeEach
        void init() {
            // (4)
            JudoModelHolder modelHolder = JudoModelHolder.
                    loadFromURL("SalesModel", new File("target/model").toURI(), new HsqldbDialect());
    
            // (5)
            injector = Guice.createInjector(
                    JudoHsqldbModules.builder().build(),
                    new SalesModelDaoModules(),
                    new JudoDefaultModule(this, modelHolder));
    
        }
    
        @Test
        public void test() {
            // (6)
            SalesPerson createdSalesPerson = salesPersonDao.create(SalesPerson.builder()
                            .withFirstName("Test")
                            .withLastName("Elek")
                            .build());
    
            assertEquals("Test", createdSalesPerson.getFirstName());
            assertEquals("Elek", createdSalesPerson.getLastName());
    
            // (7)
            List<SalesPerson> personList = salesPersonDao.search()
                            .filterByFirstName(StringFilter.equalTo("Test"))
                    .execute();
    
            assertEquals(1, personList.size());
    
            // (8)
            Person createdPerson = personDao.create(Person.builder()
                    .withFirstName("Masik")
                    .withLastName("Test")
                    .build());
    
            assertEquals("Masik", createdPerson.getFirstName());
            assertEquals("Test", createdPerson.getLastName());
    
        }
    }
    1. The Guice injector. It can use to get provided services.

    2. Injected DAO service. It is from generted SDK.

    3. Injected DAO service. It is from generted SDK.

    4. Load generated runtime models. It’s required for runtime. It is loaded from filesystem.

    5. Inject modules for generated modules. The SDK wrapper for DAO’s loaded as Guice module.

    6. Create a SalesPerson

    7. Search for created salesperson

    8. Create a Person