This plugin manages and executes generators for JUDO JSL Application codes.
It generates persitence DAO’s and Guice Injector based bootstrap.
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>
<!-- ... -->
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.
<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]
-
(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) -
(Optional) Destination path where the transformation output is generated. It contains intermediate models, traces and source code.
ImportantWhen the source codes have to be compiled, use the build-helper-plugin
to add source folder, or have to enablecompileSdk
andcreateSdkJar
option.(Default:
${project.basedir}/target/generated-sources/model
) -
(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 asmodel
in the first line of.jsl
)(Default: <none>)
-
(Optional) Which version number stored in the generated models.
(Default:
${project.version}
) -
(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 yourpom.xml
.(Default:
false
) -
(Optional) Coma separated list of dialects generated. Valid values are:
-
hsqldb,
-
postgresql
(Default:
hsqldb,postgresql
)
-
-
(Optional) Ignore Jsl2Psm work.
Default:
false
-
(Optional) Ignore Jsl2Ui work.
Default:
false
-
(Optional) Ignore Psm2Asm work.
Default:
false
-
(Optional) Ignore Psm2Asm Trace.
Default:
true
-
(Optional) Ignore Psm2Measure work.
Default:
false
-
(Optional) Ignore Psm2Measure Trace.
Default:
true
-
(Optional) Ignore Asm2Rdbms work.
Default:
false
-
(Optional) Ignore Asm2Rdbms Trace.
Default:
false
-
(Optional) Ignore Rdbms2Liquibase work.
Default:
false
-
(Optional) Ignore Asm2Expression work.
Default:
false
-
(Optional) Use cache in model transformations.
Default:
false
-
(Optional) Run in parallel when possible, parallel execution is used in multicore system
(Default:
true
) -
(Optional) Save models after execution. After execution the models are stored on destination.
(Default:
false
) -
(Optional) Enable generation time statistics after execution
(Default:
true
) -
(Optional) Validate model on load and save
(Default:
false
) -
Create simple name. (Optional) Using the model name as SQL name. It does not check namespace collosion. (Default:
false
) -
Full size of SQL name without abbreviation algorithm. When -1 is used it uses database specific default.
(Default:
-1
) -
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
) -
Table prefix used for table names. When
-
is used no prefix is used.(Default:
T_
) -
Column prefix used for column names. When
-
is used no prefix is used.(Default:
C_
) -
Foreign key prefix used for foreign key names. When
-
is used no prefix is used.(Default:
FK_
) -
Inverse Foreign key prefix used for foreign key names. When
-
is used no prefix is used.(Default:
FK_INV_
) -
Junction table prefix used for table names. When
-
is used no prefix is used.(Default:
J_
) -
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
) -
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
) -
(Optional) Ignore Asm2Keycloak work.
Default:
false
-
(Optional) Ignore Asm2Keycloak Trace.
Default:
false
-
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>
-
Runtime core version required to load end execute transformated model
-
Tatami JSL version required to transform JSL script
-
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()); } }
-
The Guice injector. It can use to get provided services.
-
Injected DAO service. It is from generted SDK.
-
Injected DAO service. It is from generted SDK.
-
Load generated runtime models. It’s required for runtime. It is loaded from filesystem.
-
Inject modules for generated modules. The SDK wrapper for DAO’s loaded as Guice module.
-
Create a SalesPerson
-
Search for created salesperson
-
Create a Person
-