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.
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>parser-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
-
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-esm-model-from-artifact</id>
<phase>compile</phase>
<goals>
<goal>default-workflow</goal>
</goals>
<configuration>
<sources>${project.basedir}/src/main/model</sources> (1)
<modelNames/> (2)
<destination>${project.basedir}/target/model</destination> (3)
<modelVersion>${project.version}</modelVersion> (4)
<sdkPackagePrefix>my.best.package</sdkPackagePrefix> (5)
<useDependencies>false</useDependencies> (6)
<createSdkJar>false</createSdkJar> (7)
<compileSdk>false</compileSdk> (8)
<dialects>hsqldb,postgresql</dialects> (9)
<ignorePsm2Asm>false</ignorePsm2Asm> (10)
<ignorePsm2AsmTrace>false</ignorePsm2AsmTrace> (11)
<ignorePsm2Measure>false</ignorePsm2Measure> (12)
<ignorePsm2MeasureTrace>false</ignorePsm2MeasureTrace> (13)
<ignoreAsm2Rdbms>false</ignoreAsm2Rdbms> (14)
<ignoreAsm2RdbmsTrace>false</ignoreAsm2RdbmsTrace> (15)
<ignoreRdbms2Liquibase>false</ignoreRdbms2Liquibase> (16)
<ignoreAsm2sdk>false</ignoreAsm2sdk> (17)
<ignoreAsm2Expression>false</ignoreAsm2Expression> (18)
<runInParallel>true</runInParallel> (19)
<saveModels>true</saveModels> (20)
<enableMetrics>true</enableMetrics> (21)
<validateModels>false</validateModels> (22)
<sdkOutputDirectory/> (23)
<sdkAddSourceToJar>true</sdkAddSourceToJar> (24)
<generateSdk>true</generateSdk> (25)
<generateSdkInternal>true</generateSdkInternal> (26)
<generateSdkGuice>false</generateSdkGuice> (27)
<generateSdkSpring>false</generateSdkSpring> (28)
<generateOptionalTypes>true</generateOptionalTypes> (29)
<generateSdkPayloadValidator>true</generateSdkPayloadValidator> (30)
</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/model directory inside the project) |
||
2 | (Optional) Destination path where the transformation output is generated. It contains intermediate models, traces and source code.
Default: |
||
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: |
||
5 | (Optional) SDK Package prefix used to store all generated model element under.
The generated Java package form <prefix>.<model fq name>.<sdk type>.<model defined packages>.<model name>
|
||
6 | (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: |
||
7 | (Optional) Create SDK Jar with pipeline. In this case the generated and compiled codes
are stored in a OSGi compliant JAR file. This JAR files can be used as dependency. When model compilation is seperated from application development these JAR files can be used as dependency, and the model loader can load models from classpath too.
(Default: |
||
8 | (Optional) In this case the pipeline calls own compiler
API to compile generated source codes. When it is true , use createSdkJar option too. |
||
9 | (Optional) Coma separated list of dialects generated. Valid values are:
|
||
10 | (Optional) Ignore Psm2Asm work.
Default: |
||
11 | (Optional) Ignore Psm2Asm Trace.
Default: |
||
12 | (Optional) Ignore Psm2Measure work.
Default: |
||
13 | (Optional) Ignore Psm2Measure Trace.
Default: |
||
14 | (Optional) Ignore Asm2Rdbms work.
Default: |
||
15 | (Optional) Ignore Asm2Rdbms Trace.
Default: |
||
16 | (Optional) Ignore Rdbms2Liquibase work.
Default: |
||
17 | (Optional) Ignore Asm2sdk work.
Default: |
||
18 | (Optional) Ignore Asm2Expression work.
Default: |
||
19 | (Optional) Run in parallel when possible, parallel execution is used in multicore system
(Default: |
||
20 | (Optional) Save models after execution. After execution the models are stored on destination.
(Default: |
||
21 | (Optional) Enable generation time statistics after execution
(Default: |
||
22 | (Optional) Validate model on load and save
(Default: |
||
23 | (Optional) When SDK output is defined, it is used instead of destination + modelName.
(Default: |
||
24 | (Optional) Add generared codes to JAR files. To work the createSdkJar option
have to be enabled.
(Default: |
||
25 | (Optional) Generate SDK interfaces. When internal, guice or spring is generated, it have to be enabled
(Default: |
||
26 | (Optional) Generate Internal Wrapper implementation. When guice or spring is generated, it have to be enabled
(Default: |
||
27 | (Optional) Generate Guice SDK implementation.
(Default: |
||
28 | (Optional) Generate Spring SDK implementation.
(Default: |
||
29 | (Optional) Generate Optional types. It generates
Optional wrapper for Transfer Object fields and for single relations
where the cardinality is 0
(Default: |
||
30 | (Optional) Generate SDK Payload validation on DAO calls.
(Default: |
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>parser-workflow</goal> </goals> <phase>generate-sources</phase> </execution> </executions> <configuration> <modelNames>SalesModel</modelNames> <sources>${basedir}/src/main/model</sources> <sdkPackagePrefix>hu.blackbelt.judo.test</sdkPackagePrefix> <dialects>hsqldb</dialects> <generateSdkGuice>true</generateSdkGuice> </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-bootstrap-hsqldb</artifactId> </dependency> <dependency> <groupId>hu.blackbelt.judo.runtime</groupId> <artifactId>judo-runtime-core-bootstrap-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.bootstrap.JudoDefaultModule; import hu.blackbelt.judo.runtime.core.bootstrap.JudoModelHolder; import hu.blackbelt.judo.runtime.core.bootstrap.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