diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..529d1b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+/plantuml/
+/sql/
+/src/
+/pom_jpa.xml
+/TelosysTools/downloads
+/TelosysTools/templates
+!/TelosysTools/templates/infinimotion
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..8780e86
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/model.iml b/.idea/model.iml
new file mode 100644
index 0000000..cebd128
--- /dev/null
+++ b/.idea/model.iml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..b4722af
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..8306744
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TelosysTools/databases.yaml b/TelosysTools/databases.yaml
new file mode 100644
index 0000000..c04da28
--- /dev/null
+++ b/TelosysTools/databases.yaml
@@ -0,0 +1,47 @@
+# Telosys databases configuration
+#
+# . id : must be unique (database identifier)
+#
+# "metadata" configuration :
+# . catalog : the catalog where to search the metadata ( "!" means "null" )
+# . schema : the schema where to search the metadata ( "!" means "null" )
+# . tableNamePattern : the pattern used as table name filter ( ex : "%", "A%", ... )
+# . tableTypes : the types to retrieve, separated by blanks ( ex : "TABLE", "TABLE VIEW", ... )
+# . tableNameExclude : the pattern used to exclude tables
+# . tableNameInclude : the pattern used to include tables
+#
+# NB: this a YAML file, don't forget to use QUOTES when a special character is used
+
+databases :
+# PostgreSQL database identified by "pg"
+ - id: pg
+ name: PostgreSQL database
+ type: POSTGRESQL
+ # JDBC driver
+ driver: org.postgresql.Driver
+ # JDBC url: jdbc:postgresql://{HOST}:{PORT}/{DATABASE}
+ url: jdbc:postgresql://myhost:5432/mydatabase
+ user: bob
+ password: secret
+ # Metadata parameters
+ catalog: '!'
+ # schema: '!' ok to get tables but not to get columns, etc
+ schema: public
+ tableNamePattern:
+ tableNameInclude:
+ tableNameExclude:
+ tableTypes: TABLE
+ #--- Telosys model creation
+ # what kind of links to define in the model
+ linksManyToOne: true
+ linksOneToMany: false
+ linksManyToMany: false
+ # what kind of database information to define in the model (true for all by default)
+ dbComment: false
+ dbCatalog : true
+ dbSchema : true
+ dbTable : true
+ dbView : false
+ dbName : true
+ dbType : true
+ dbDefaultValue: false
\ No newline at end of file
diff --git a/TelosysTools/models/InfiniMotion/Eintrittskarte.entity b/TelosysTools/models/InfiniMotion/Eintrittskarte.entity
new file mode 100644
index 0000000..c886415
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Eintrittskarte.entity
@@ -0,0 +1,9 @@
+// Entity Eintrittskarte
+
+Eintrittskarte {
+ id: int { @Id @AutoIncremented } ;
+ show: Vorstellung {} ;
+ seat: Sitzplatz {} ;
+ code: string {} ;
+ state: Kartenstatus {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Film.entity b/TelosysTools/models/InfiniMotion/Film.entity
new file mode 100644
index 0000000..b23a24b
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Film.entity
@@ -0,0 +1,11 @@
+// Entity Film
+
+Film {
+ id: int { @Id @AutoIncremented } ;
+ title: string {} ;
+ description: string {} ;
+ duration: int {} ;
+ image: string {} ;
+ rating: short {} ;
+ category: Filmkategorie {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Filmkategorie.entity b/TelosysTools/models/InfiniMotion/Filmkategorie.entity
new file mode 100644
index 0000000..f65d749
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Filmkategorie.entity
@@ -0,0 +1,6 @@
+// Entity Filmkategorie
+
+Filmkategorie {
+ id: int { @Id @AutoIncremented } ;
+ name: string {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Kartenstatus.entity b/TelosysTools/models/InfiniMotion/Kartenstatus.entity
new file mode 100644
index 0000000..582734e
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Kartenstatus.entity
@@ -0,0 +1,6 @@
+// Entity Kartenstatus
+
+Kartenstatus {
+ id: int { @Id @AutoIncremented } ;
+ name: string {} ;
+}
\ No newline at end of file
diff --git a/TelosysTools/models/InfiniMotion/Kinosaal.entity b/TelosysTools/models/InfiniMotion/Kinosaal.entity
new file mode 100644
index 0000000..bc90ea5
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Kinosaal.entity
@@ -0,0 +1,6 @@
+// Entity Kinosaal
+
+Kinosaal {
+ id : int { @Id @AutoIncremented } ;
+ name : string {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Sitzkategorie.entity b/TelosysTools/models/InfiniMotion/Sitzkategorie.entity
new file mode 100644
index 0000000..0c039bf
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Sitzkategorie.entity
@@ -0,0 +1,6 @@
+// Entity Sitzkategorie
+
+Sitzkategorie {
+ id: int { @Id @AutoIncremented } ;
+ name: string { } ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Sitzplatz.entity b/TelosysTools/models/InfiniMotion/Sitzplatz.entity
new file mode 100644
index 0000000..f175cbb
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Sitzplatz.entity
@@ -0,0 +1,7 @@
+// Entity Sitzplatz
+
+Sitzplatz {
+ id: int { @Id @AutoIncremented } ;
+ row: Sitzreihe {} ;
+ position: int {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Sitzreihe.entity b/TelosysTools/models/InfiniMotion/Sitzreihe.entity
new file mode 100644
index 0000000..cece3f1
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Sitzreihe.entity
@@ -0,0 +1,8 @@
+// Entity Sitzreihe
+
+Sitzreihe {
+ id: int { @Id @AutoIncremented } ;
+ hall: Kinosaal {} ;
+ position: int {} ;
+ category: Sitzkategorie {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/Vorstellung.entity b/TelosysTools/models/InfiniMotion/Vorstellung.entity
new file mode 100644
index 0000000..97ed45d
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/Vorstellung.entity
@@ -0,0 +1,8 @@
+// Entity Vorstellung
+
+Vorstellung {
+ id: int { @Id @AutoIncremented } ;
+ hall: Kinosaal {} ;
+ movie: Film {} ;
+ start: date {} ;
+}
diff --git a/TelosysTools/models/InfiniMotion/model.yaml b/TelosysTools/models/InfiniMotion/model.yaml
new file mode 100644
index 0000000..ee1c1f5
--- /dev/null
+++ b/TelosysTools/models/InfiniMotion/model.yaml
@@ -0,0 +1,4 @@
+# Telosys model info
+title: InfiniModel
+version: 1.0.0
+description: InfiniMotion-Model
diff --git a/TelosysTools/telosys-tools.cfg b/TelosysTools/telosys-tools.cfg
new file mode 100644
index 0000000..74cbf6b
--- /dev/null
+++ b/TelosysTools/telosys-tools.cfg
@@ -0,0 +1,57 @@
+# Telosys-Tools properties
+# -------------------------------------------
+# --- Project folders (standard variables)
+SRC=src/main/java
+RES=src/main/resources
+WEB=src/main/webapp
+TEST_SRC=src/test/java
+TEST_RES=src/test/resources
+#SRC=src
+#RES=res
+#WEB=WebContent
+#TEST_SRC=src
+#TEST_RES=
+DOC=doc
+TMP=tmp
+# -------------------------------------------
+# --- Project Packages (standard variables)
+ROOT_PKG=de.infinimotion
+ENTITY_PKG=de.infinimotion.bean
+# -------------------------------------------
+# --- Project Specific Variables
+ProjectVariable.MAVEN_ARTIFACT_ID=infinimodel
+ProjectVariable.MAVEN_GROUP_ID=de.infinimotion
+ProjectVariable.PROJECT_NAME=infinimodel
+ProjectVariable.PROJECT_VERSION=0.1
+ProjectVariable.REST_SERVER_PORT=3000
+ProjectVariable.REST_API_ROOT=/api/v1
+ProjectVariable.REST_URL_ROOT=http://localhost:3000
+# -------------------------------------------
+#----- Project Specific Folders (use absolute path)
+#-- Specific destination for code generation :
+# SpecificDestinationFolder=C:/dir1/dir2
+# SpecificDestinationFolder=/dir1/dir2
+#-- Specific location for templates :
+# SpecificTemplatesFolder=C:/dir1/dir2
+# SpecificTemplatesFolder=/dir1/dir2
+#-- Specific location for models (since ver 4.2.0) :
+# SpecificModelsFolder=C:/dir1/dir2
+# SpecificModelsFolder=/dir1/dir2
+#-- Specific depots in GitHub for bundles and models (since ver 4.2.0) :
+# SpecificDepotForBundles=github_user:user-name
+# SpecificDepotForBundles=github_org:my-organization(https://myhost)
+# SpecificDepotForModels=github_user:foobar
+# SpecificDepotForModels=github_org:my-orga
+# -------------------------------------------
+# --- Network proxy configuration
+# http.proxyHost=my.proxy.hostname
+# http.proxyPort=8080
+# http.nonProxyHosts=localhost|127.0.0.1
+# http.proxyUser=foo
+# http.proxyPassword=secret
+#--
+# https.proxyHost=my.proxy.hostname
+# https.proxyPort=8080
+# https.nonProxyHosts=localhost|127.0.0.1
+# https.proxyUser=foo
+# https.proxyPassword=secret
diff --git a/TelosysTools/telosys.env b/TelosysTools/telosys.env
new file mode 100644
index 0000000..3ce7d13
--- /dev/null
+++ b/TelosysTools/telosys.env
@@ -0,0 +1,4 @@
+#
+#Thu Oct 16 17:17:54 CEST 2025
+bundle=infinimotion
+model=InfiniMotion
diff --git a/TelosysTools/templates/infinimotion/README.md b/TelosysTools/templates/infinimotion/README.md
new file mode 100644
index 0000000..ad87140
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/README.md
@@ -0,0 +1,42 @@
+# Telosys bundle of templates for basic Java domain classes
+
+This bundle is available for demonstration and learning purposes to get started with Telosys
+
+It generates very basic Java domain classes (pure Java without dependencies)
+
+A domain class is generated for each entity with a basic JUnit test case
+
+# JPA entities with JUnit test cases
+
+This bundle generates the following Java files:
+
+- in "**project-root**"
+ - **pom_jpa.xml** : a "pom.xml" file for JPA (designed to be renamed to "pom.xml")
+
+- in "**src/main/java/{package}/entities**"
+ - **{entity-name}.java** : JPA entity (with JPA annotations)
+ - **{entity-name}Id.java** : JPA composite primary key (if any)
+
+- in "**src/main/resources/META-INF**"
+ - **persistence.xml** : a JPA configuration file example
+
+- in "**src/test/java/{package}/entities**"
+ - **{entity-name}JpaTest.java** : JPA JUnit test case
+
+- in "**src/test/java/jpa/data**"
+ - **{entity-name}Data.java** : JPA data initialization
+
+- in "**src/test/java/jpa/tools**"
+ - **DatabaseInit.java** : Database initialization before unit tests
+ - **JpaTest.java** : abstract class for JPA JUnit test
+
+- in "**src/test/resources/META-INF**"
+ - **persistence.xml** : the JPA configuration file for test cases with H2 database
+
+
+
+# PlantUML diagram
+
+This bunldle aims to generate PlantUML diagram files ( https://plantuml.com/ ).
+
+It allows to transform a Telosys model to a PlantUML model.
diff --git a/TelosysTools/templates/infinimotion/class-diag_txt.vm b/TelosysTools/templates/infinimotion/class-diag_txt.vm
new file mode 100644
index 0000000..5c34ddc
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/class-diag_txt.vm
@@ -0,0 +1,81 @@
+## -----------------------------------------------------------------------
+## Basic link from entity A to entity B
+#macro( links $entitiesList )
+## Links relations
+#foreach( $entity in $entitiesList )
+#foreach( $link in $entity.selectedLinks )
+#set($cardinality = "1" )
+#if ( $link.isCollectionType() )
+#set($cardinality = "N" )
+#end
+$entity.name --> "$cardinality" $link.targetEntity.name
+#end
+#end
+#end
+## -----------------------------------------------------------------------
+## Link from "entity field" to another entity
+#macro( linksFromFields $entitiesList )
+#foreach( $entity in $entitiesList )
+#foreach( $link in $entity.selectedLinks )
+#set($cardinality = "1" )
+#if ( $link.isCollectionType() )
+#set($cardinality = "N" )
+#end
+${entity.name}::${link.fieldName} --> "$cardinality" $link.targetEntity.name
+#end
+#end
+#end
+## -----------------------------------------------------------------------
+#macro( basicLink $entity $link $cardinality )
+$entity.name --> "$cardinality" $link.targetEntity.name
+#end
+## -----------------------------------------------------------------------
+#macro( linkFromField $entity $link $cardinality )
+${entity.name}::${link.fieldName} --> "$cardinality" $link.targetEntity.name
+#end
+## -----------------------------------------------------------------------
+@startuml
+
+## --- Model description note
+note as TelosysDiagramTitleNote
+ Model $model.name
+ generated by Telosys
+ $now.date ( $now.time )
+end note
+
+## --- Classes (based on model entities)
+#foreach( $entity in $selectedEntities )
+class $entity.name #if ( $entity.isJoinEntity() ) << (J,AliceBlue) Join Entity >> #else << (E,cornsilk) >> #end {
+#foreach( $attribute in $entity.keyAttributes )
+ + $attribute.name : $attribute.neutralType {PK} #if ($attribute.isFK() ){FK}#end
+
+#end
+ ....
+#foreach( $attribute in $entity.nonKeyAttributes )
+ + $attribute.name : $attribute.neutralType #if ($attribute.isFK() ){FK}#end
+
+#end
+ ....
+#foreach( $link in $entity.selectedLinks )
+ + $link.fieldName : $link.fieldType
+#end
+}
+#end
+
+## --- Links between classes
+## Choose link type here :
+## #links ( $selectedEntities )
+## #linksFromFields( $selectedEntities )
+#foreach( $entity in $selectedEntities )
+#foreach( $link in $entity.selectedLinks )
+#set($cardinality = "1" )
+#if ( $link.isCollectionType() )
+#set($cardinality = "N" )
+#end
+## Choose link type here :
+## #basicLink( $entity, $link, $cardinality )
+#linkFromField( $entity, $link, $cardinality )
+#end
+#end
+
+@enduml
diff --git a/TelosysTools/templates/infinimotion/domain_entity_java.vm b/TelosysTools/templates/infinimotion/domain_entity_java.vm
new file mode 100644
index 0000000..5a0e2ef
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/domain_entity_java.vm
@@ -0,0 +1,107 @@
+/*
+ * Java domain class for entity "${entity.name}"
+ * Created on $now.date ( $now.time )
+ * Generated by $generator.name ( version $generator.version )
+ */
+package ${target.javaPackageFromFolder(${SRC})};
+
+import java.io.Serializable;
+
+#foreach( $import in $java.imports($entity) )
+import $import;
+#end
+
+##--------------------------------------------------------------------------------------------------------
+## Data fields = fields not in Primary Key and not in selected Links
+#set( $dataFields = $entity.getAttributesByCriteria( $const.NOT_KEY, $const.NOT_IN_SELECTED_LINKS ) )
+##--------------------------------------------------------------------------------------------------------
+## Link fields = fields not in Primary Key and used as FK in selected Links
+#set( $linkFields = $entity.getAttributesByCriteria( $const.NOT_KEY, $const.IN_SELECTED_LINKS ) )
+##--------------------------------------------------------------------------------------------------------
+/**
+ * Domain class for entity "${entity.name}"
+ *
+ * @author Telosys Tools Generator
+ *
+ */
+public class ${entity.name} implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ //----------------------------------------------------------------------
+ // ENTITY PRIMARY KEY
+ //----------------------------------------------------------------------
+#foreach( $field in $entity.keyAttributes )
+ private $field.formattedType(10) $field.formattedName(12) #if($field.hasInitialValue())= ${field.initialValue} #end;
+#end
+
+ //----------------------------------------------------------------------
+ // ENTITY DATA FIELDS
+ //----------------------------------------------------------------------
+#foreach( $field in $dataFields )
+ private $field.formattedType(10) $field.formattedName(12) #if($field.hasInitialValue())= ${field.initialValue} #end;
+#end
+#foreach( $field in $linkFields )
+ // Attribute "$field.name" is a link
+#end
+
+ //----------------------------------------------------------------------
+ // ENTITY LINKS ( RELATIONSHIP )
+ //----------------------------------------------------------------------
+#foreach( $link in $entity.selectedLinks )
+ private ${link.formattedFieldType(10)} $link.formattedFieldName(12) ;
+#end
+
+ //----------------------------------------------------------------------
+ // CONSTRUCTOR(S)
+ //----------------------------------------------------------------------
+ public ${entity.name}() {
+ super();
+ }
+
+ //----------------------------------------------------------------------
+ // GETTER & SETTER FOR "KEY FIELD(S)"
+ //----------------------------------------------------------------------
+#foreach( $attribute in $entity.keyAttributes )
+ public void ${attribute.setter}( $attribute.type $attribute.name ) {
+ this.$attribute.name = $attribute.name ;
+ }
+ public $attribute.type ${attribute.getter}() {
+ return this.$attribute.name;
+ }
+
+#end
+
+ //----------------------------------------------------------------------
+ // GETTERS & SETTERS FOR "DATA FIELDS"
+ //----------------------------------------------------------------------
+#foreach( $attribute in $dataFields )
+ public void ${attribute.setter}( $attribute.type $attribute.name ) {
+ this.$attribute.name = $attribute.name ;
+ }
+ public $attribute.type ${attribute.getter}() {
+ return this.$attribute.name;
+ }
+
+#end
+
+ //----------------------------------------------------------------------
+ // GETTERS & SETTERS FOR LINKS
+ //----------------------------------------------------------------------
+#foreach( $link in $entity.selectedLinks )
+ public void ${link.setter}( ${link.formattedFieldType(0)} ${link.formattedFieldName(0)} ) {
+ this.${link.formattedFieldName(0)} = ${link.formattedFieldName(0)};
+ }
+ public ${link.formattedFieldType(0)} ${link.getter}() {
+ return this.${link.formattedFieldName(0)};
+ }
+
+#end
+
+ //----------------------------------------------------------------------
+ // toString METHOD
+ //----------------------------------------------------------------------
+## This function generates a 'toString' method with 4 blanks before each line
+## $java.toStringMethod($fn.concatLists($entity.keyAttributes, $dataFields), 4)
+$java.toStringMethod($entity, 1)
+}
diff --git a/TelosysTools/templates/infinimotion/domain_entity_test_java.vm b/TelosysTools/templates/infinimotion/domain_entity_test_java.vm
new file mode 100644
index 0000000..45aab4b
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/domain_entity_test_java.vm
@@ -0,0 +1,52 @@
+/*
+ * JUnit test case for bean $entity.name
+ * Created on $now.date ( $now.time )
+ * Generated by $generator.name ( version $generator.version )
+ */
+
+package ${target.javaPackageFromFolder(${TEST_SRC})};
+
+## Same package => no need to import 'Record' class //import $entity.name ;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * JUnit test case for bean $entity.name
+ *
+ * @author Telosys Tools Generator
+ *
+ */
+#set ( $beanVar = ${fn.uncapitalize($entity.name)} )
+public class ${entity.name}Test
+{
+
+ @Test
+ public void testSettersAndGetters() {
+
+ System.out.println("Checking class ${entity.name} getters and setters ..." );
+
+ ${entity.name} ${beanVar} = new ${entity.name}();
+
+## #set( $values = $fn.buildValues($entity.attributes, 1) )
+#set( $attributesToBeTested = $entity.getAttributesByCriteria( $const.NOT_IN_LINKS ) )
+#set( $values = $fn.buildValues($attributesToBeTested, 1) )
+
+
+## #foreach( $attribute in $entity.attributes )
+#foreach( $attribute in $attributesToBeTested )
+#set( $value = $values.getValue($attribute.name) )
+ //--- Test setter/getter for attribute "$attribute.name" ( type : $attribute.type )
+ ${beanVar}.${attribute.setter}( $value ) ;
+#if ( $value == "null" )
+ Assert.assertNull(${beanVar}.${attribute.getter}());
+#else
+ Assert.assertEquals( $value, ${beanVar}.${attribute.getter}() ) ;
+#end
+
+#end
+ }
+
+
+
+}
diff --git a/TelosysTools/templates/infinimotion/include/init_var_entity.vm b/TelosysTools/templates/infinimotion/include/init_var_entity.vm
new file mode 100644
index 0000000..b310f7e
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/include/init_var_entity.vm
@@ -0,0 +1,9 @@
+## #set($recordClass = "${entity.name}Record" )
+## #set($recordInstance = $fn.uncapitalize($entity.name) )
+##
+#set($jpaEntityClass = "${entity.name}" )
+#set($jpaEntityIdClass = "${entity.name}Id" )
+##
+## #set($jpaMapperClass = "${entity.name}RecordMapper" )
+## #set($jpaMapperInstance = "${recordInstance}Mapper" )
+##
diff --git a/TelosysTools/templates/infinimotion/include/java_header.vm b/TelosysTools/templates/infinimotion/include/java_header.vm
new file mode 100644
index 0000000..313ba99
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/include/java_header.vm
@@ -0,0 +1,4 @@
+/*
+ * Created on $now.date ( $now.time )
+ * Generated by Telosys ( http://www.telosys.org/ ) version $generator.version
+ */
diff --git a/TelosysTools/templates/infinimotion/main-java/XxxJpaEntityId_java.vm b/TelosysTools/templates/infinimotion/main-java/XxxJpaEntityId_java.vm
new file mode 100644
index 0000000..e45e427
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/main-java/XxxJpaEntityId_java.vm
@@ -0,0 +1,78 @@
+#checkId($entity)
+#parse("include/init_var_entity.vm")
+#parse("include/java_header.vm")
+##--------------------------------------------------------------------------------------------------------
+package ${target.javaPackageFromFolder($SRC)};
+
+import java.io.Serializable;
+
+#foreach( $import in $java.imports($entity.keyAttributes) )
+import $import;
+#end
+
+/**
+ * Composite primary key for entity "${entity.name}" ( stored in table "${entity.databaseTable}" )
+ *
+ * @author Telosys
+ *
+ */
+## @Embeddable
+public class $jpaEntityIdClass implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ //--- ENTITY KEY ATTRIBUTES
+#foreach( $field in $entity.keyAttributes )
+## $jpa.embeddedIdAnnotations(4, $field)
+ private $field.formattedType(10) $field.name ;
+
+#end
+ /**
+ * Constructor
+ */
+ public $jpaEntityIdClass() {
+ super();
+ }
+
+ /**
+ * Constructor with values
+#foreach( $field in $entity.keyAttributes )
+ * @param $field.name
+#end
+ */
+ public ${jpaEntityIdClass}( $fn.argumentsListWithWrapperType($entity.keyAttributes) ) {
+ super();
+#foreach( $field in $entity.keyAttributes )
+ this.$field.name = $field.name ;
+#end
+ }
+
+ //--- GETTERS & SETTERS FOR KEY FIELDS
+#foreach( $field in $entity.keyAttributes )
+#if ( $field.databaseName )
+#end
+#if ( $field.setter ) public void ${field.setter}( $field.type value ) {
+ this.$field.name = value;
+ }
+#end
+#if ( $field.getter ) public $field.type ${field.getter}() {
+ return this.$field.name;
+ }
+#end
+
+#end
+
+ //--- equals METHOD
+ @Override
+$java.equalsMethod($jpaEntityIdClass, $entity.keyAttributes )## no EOL
+
+ //--- hashCode METHOD
+ @Override
+$java.hashCodeMethod($jpaEntityIdClass, $entity.keyAttributes )## no EOL
+
+ //--- toString METHOD
+ @Override
+## $java.toStringMethod($entity.keyAttributes, 4)## no EOL
+$java.toStringMethod($entity, $entity.keyAttributes, 1)
+
+}
diff --git a/TelosysTools/templates/infinimotion/main-java/XxxJpaEntity_java.vm b/TelosysTools/templates/infinimotion/main-java/XxxJpaEntity_java.vm
new file mode 100644
index 0000000..b9fe64a
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/main-java/XxxJpaEntity_java.vm
@@ -0,0 +1,125 @@
+## --------------------------------------------------
+#if ( $entity.isJoinEntity() )
+#cancel("No JPA class for join entity")
+#end
+## --------------------------------------------------
+#checkId($entity)
+#parse("include/init_var_entity.vm")
+#parse("include/java_header.vm")
+##---------------------------------------------------------------------------------------
+## JPA CONFIGURATION
+##---------------------------------------------------------------------------------------
+## Define the default collection type to be used (default is "java.util.List" )
+## #set($env.collectionType = "java.util.Set")
+## #set($env.collectionType = "java.util.Collection")
+## ---------------------------
+## Define if "targetEntity" must be generated in @ManyToMany or @OneToMany
+## #set($jpa.genTargetEntity = true)
+## ---------------------------
+## Define default value (true or false) for "insertable" and "updatable" in "@JoinColumn"
+## #set($jpa.joinColumnInsertable = true)
+## #set($jpa.joinColumnUpdatable = true)
+## ---------------------------
+## Set default FETCH-TYPE for each cardinality ( "LAZY" or "EAGER" )
+## #set($jpa.manyToOneFetchType = "LAZY" )
+## #set($jpa.oneToOneFetchType = "LAZY" )
+## #set($jpa.oneToManyFetchType = "EAGER" )
+## #set($jpa.manyToManyFetchType = "EAGER" )
+##---------------------------------------------------------------------------------------
+package ${target.javaPackageFromFolder(${SRC})};
+## IF ENTITY HAS A COMPOSITE PRIMARY KEY => GENERATE AN 'ID CLASS' FOR THIS PRIMARY KEY
+#if ( $entity.hasCompositePrimaryKey() )
+$generator.generate($target.entityName , "${jpaEntityIdClass}.java", $target.folder, "main-java/XxxJpaEntityId_java.vm" )
+#end
+
+import java.io.Serializable;
+#foreach( $import in $java.imports($entity) )
+import $import;
+#end
+#foreach( $import in $jpa.imports($entity) )
+import $import;
+#end
+
+/**
+ * JPA entity class for "${entity.name}"
+ *
+ * @author Telosys
+ *
+ */
+$jpa.entityAnnotations(0, $entity)
+## IF ENTITY HAS A COMPOSITE PRIMARY KEY => DECLARE 'ID CLASS' FOR THIS PRIMARY KEY
+#if ( $entity.hasCompositePrimaryKey() )
+@IdClass(${jpaEntityIdClass}.class)
+#end
+public class ${entity.name} implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ //--- ENTITY PRIMARY KEY
+#foreach( $attribute in $entity.keyAttributes )
+$jpa.fieldAnnotations(4, $attribute)
+ private $attribute.formattedType(10) $attribute.name #if($attribute.hasInitialValue())= ${attribute.ini} #end;
+
+#end
+ //--- ENTITY DATA FIELDS
+#foreach( $attribute in $entity.nonKeyAttributes )
+$jpa.fieldAnnotations(4, $attribute)
+ private $attribute.formattedType(10) $attribute.name #if($attribute.hasInitialValue())= ${attribute.ini} #end;
+
+#end
+
+ //--- ENTITY LINKS ( RELATIONSHIP )
+#foreach( $link in $entity.links )
+## all annotations : Cardinality, JoinColumn(s), etc
+##--- with "insertable=false, updatable=false" if attribute already mapped
+$jpa.linkAnnotations(4, $link, $entity.attributes)
+##--- no "insertable=false, updatable=false" if already mapped
+## $jpa.linkAnnotations(4, $link)
+##--- Just @Cardinality annotation
+## $jpa.linkCardinalityAnnotation(4, $link)
+##--- Just @JoinColumn(s) annotation(s)
+## $jpa.linkJoinAnnotation(4, $link)
+## $jpa.linkJoinAnnotation(4, $link, $entity.attributes)
+ private ${link.formattedFieldType(10)} $link.fieldName ;
+
+#end
+
+ /**
+ * Constructor
+ */
+ public ${entity.name}() {
+ super();
+ }
+
+ //--- GETTERS & SETTERS FOR FIELDS
+#foreach( $attribute in $entity.keyAttributes )
+ public void ${attribute.setter}( $attribute.type $attribute.name ) {
+ this.$attribute.name = $attribute.name ;
+ }
+ public $attribute.type ${attribute.getter}() {
+ return this.$attribute.name;
+ }
+
+#end
+#foreach( $attribute in $entity.nonKeyAttributes )
+ public void ${attribute.setter}( $attribute.type $attribute.name ) {
+ this.$attribute.name = $attribute.name ;
+ }
+ public $attribute.type ${attribute.getter}() {
+ return this.$attribute.name;
+ }
+
+#end
+ //--- GETTERS FOR LINKS
+#foreach( $link in $entity.selectedLinks )
+ public ${link.formattedFieldType(0)} ${link.getter}() {
+ return this.${link.formattedFieldName(0)};
+ }
+
+#end
+ //--- toString specific method
+ @Override
+## This function generates a 'toString' method with indentation level = 1 (1 tab)
+## $java.toStringMethod($fn.concatLists($entity.keyAttributes, $entity.nonKeyAttributes), 4)## no EOL
+$java.toStringMethod($entity, 1)
+}
diff --git a/TelosysTools/templates/infinimotion/main-resources/persistence_xml.vm b/TelosysTools/templates/infinimotion/main-resources/persistence_xml.vm
new file mode 100644
index 0000000..e6fc8a8
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/main-resources/persistence_xml.vm
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ org.hibernate.ejb.HibernatePersistence
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TelosysTools/templates/infinimotion/mydbrules.properties b/TelosysTools/templates/infinimotion/mydbrules.properties
new file mode 100644
index 0000000..d6674d3
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/mydbrules.properties
@@ -0,0 +1,55 @@
+#########################################
+## NAMES CONVERSION
+#########################################
+
+# Table name conversion : camelCase, PascalCase, snake_case, ANACONDA_CASE
+conv.tableName = ANACONDA_CASE
+
+# Column name conversion : camelCase, PascalCase, snake_case, ANACONDA_CASE
+conv.columnName = ANACONDA_CASE
+
+# Primary Key name conversion : camelCase, PascalCase, snake_case, ANACONDA_CASE
+conv.pkName = ANACONDA_CASE
+
+# Foreign Key name conversion : camelCase, PascalCase, snake_case, ANACONDA_CASE
+conv.fkName = ANACONDA_CASE
+
+
+##############################################
+# TYPES CONVERSION (model type to SQL type)
+##############################################
+
+# (%s) size is optional, (%S) size is mandatory
+type.string = varchar(%s)
+# type.string = varchar(%S)
+
+type.byte = smallint
+type.byte.autoincr = smallserial
+
+type.short = smallint
+type.short.autoincr = smallserial
+
+type.int = INTEGER
+type.int.autoincr = serial
+
+type.long = bigint
+type.long.autoincr = bigserial
+
+# (%p) precision is optional, (%P) precision is mandatory
+type.decimal = numeric(%p)
+# type.decimal = numeric(%P)
+
+type.float = real
+type.double = double precision
+
+type.boolean = boolean
+
+type.date = date
+
+type.time = time
+# type.time = time with time zone
+
+type.timestamp = timestamp
+# type.timestamp = timestamp with time zone
+
+type.binary = bytea
diff --git a/TelosysTools/templates/infinimotion/pom_jpa_xml.vm b/TelosysTools/templates/infinimotion/pom_jpa_xml.vm
new file mode 100644
index 0000000..634190c
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/pom_jpa_xml.vm
@@ -0,0 +1,56 @@
+
+
+
+
+ 4.0.0
+ $fn.get("MAVEN_GROUP_ID","to.be.defined")
+ $fn.get("MAVEN_ARTIFACT_ID","to.be.defined")
+ $fn.get("PROJECT_VERSION","1.0.0")
+ jar
+
+
+ UTF-8
+
+
+
+
+
+
+ org.hibernate
+ hibernate-entitymanager
+ 5.4.18.Final
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ com.h2database
+ h2
+ 1.4.200
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.5.1
+
+ 1.8
+ 1.8
+
+
+
+
+
+
diff --git a/TelosysTools/templates/infinimotion/postgresql-create-tables_sql.vm b/TelosysTools/templates/infinimotion/postgresql-create-tables_sql.vm
new file mode 100644
index 0000000..a377004
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/postgresql-create-tables_sql.vm
@@ -0,0 +1,45 @@
+-- Generated by Telosys ( https://www.telosys.org/ )
+-- $now.date ($now.time)
+#set( $env.database = 'PostgreSQL' )
+## ---------------------------------------
+## For each entity : CREATE TABLE
+## ---------------------------------------
+#foreach( $entity in $model.allEntites )
+## CREATE TABLE IF NOT EXISTS $entity.sqlTableName
+## use $entity.databaseSchema if necessary
+CREATE TABLE $entity.sqlTableName
+(
+## COLUMNS DEFINITION :
+#foreach( $attribute in $entity.attributes )
+#if( $foreach.hasNext() || $entity.hasPrimaryKey() )
+#set($EOL=",")
+#else
+#set($EOL="")
+#end
+## $sql.columnName($attribute) $sql.columnType($attribute) $sql.columnConstraints($attribute)$EOL
+ $attribute.sqlColumnName $attribute.sqlColumnType ${attribute.sqlColumnConstraints}$EOL
+#end
+## PRIMARY KEY DEFINITION :
+#if( $entity.hasPrimaryKey() )
+## PRIMARY KEY ($sql.pkColumns($entity))
+ PRIMARY KEY ($entity.sqlPrimaryKeyColumnsAsString)
+#end
+);
+
+#end## foreach( $entity )
+
+## ---------------------------------------------------------
+## For each Foreign Key in each entity : CREATE FOREIGN KEY
+## ---------------------------------------------------------
+#foreach( $entity in $model.allEntites )
+#if ( $entity.hasForeignKeys() )
+#set($tableName = $entity.sqlTableName )
+#foreach( $fk in $entity.databaseForeignKeys )
+ALTER TABLE $tableName
+ ADD CONSTRAINT "$fk.name" FOREIGN KEY($fk.sqlOriginColumnsAsString)
+ REFERENCES ${fk.sqlReferencedTableName}($fk.sqlReferencedColumnsAsString) ;
+CREATE INDEX ON $tableName($fk.sqlOriginColumnsAsString) ;
+#end## foreach( $fk )
+
+#end## if has FK
+#end## foreach( $entity )
diff --git a/TelosysTools/templates/infinimotion/templates.cfg b/TelosysTools/templates/infinimotion/templates.cfg
new file mode 100644
index 0000000..91a3d83
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/templates.cfg
@@ -0,0 +1,34 @@
+#---------------------------------------------------------
+# Templates bundle configuration file
+# 5 values separated by ";"
+# . value 1 : the label to be displayed
+# . value 2 : the file to be generated ( with variables replacement : ${BEANNAME}, ${BEANNAME_UC}, ${BEANNAME_LC} )
+# . value 3 : the project folder where to generate ( with variables replacement )
+# . value 4 : the template to use
+# . value 5 : number of execution : "1" for "ONCE" for all entities, default is multiple executions ( executed for each entity )
+#---------------------------------------------------------
+
+Model diagram ; model.plantuml ; plantuml ; class-diag_txt.vm ; 1
+
+# PostgreSQL database
+PostgreSQL create tables ; postgresql-create-tables.sql ; sql ; postgresql-create-tables_sql.vm ; 1
+
+# Domain class ( keep same package for tests classes )
+Java domain class (bean) ; ${BEANNAME}.java ; ${SRC}/${ROOT_PKG}/data/domain ; domain_entity_java.vm
+Java domain class JUnit test ; ${BEANNAME}Test.java ; ${TEST_SRC}/${ROOT_PKG}/data/domain ; domain_entity_test_java.vm
+
+#--- Project root folder
+Maven pom.xml ; pom_jpa.xml ; ; pom_jpa_xml.vm ; 1
+
+#--- JPA entities
+Java JPA entity class ; ${BEANNAME}.java ; ${SRC}/${ROOT_PKG}/entities ; main-java/XxxJpaEntity_java.vm
+#--- JPA resources
+persistence.xml ; persistence.xml ; ${RES}/META-INF ; main-resources/persistence_xml.vm ; 1
+# persistence.properties ; persistence.properties ; ${RES}/META-INF ; main-resources/persistence_properties.vm ; 1
+
+#--- src/test/java
+Tests : generic class ; JpaTest.java ; ${TEST_SRC}/${ROOT_PKG}/entities/tooling ; test-java/JpaTest_java.vm ; 1
+Tests : database init ; DatabaseInit.java ; ${TEST_SRC}/${ROOT_PKG}/entities/tooling ; test-java/DatabaseInit_java.vm ; 1
+Tests : entity tests ; ${BEANNAME}JpaTest.java ; ${TEST_SRC}/${ROOT_PKG}/entities ; test-java/XxxJpaTest_java.vm ; *
+#--- src/test/resources
+Tests : persistence.xml ; persistence.xml ; ${TEST_RES}/META-INF ; test-resources/persistence_xml.vm ; 1
\ No newline at end of file
diff --git a/TelosysTools/templates/infinimotion/test-java/DatabaseInit_java.vm b/TelosysTools/templates/infinimotion/test-java/DatabaseInit_java.vm
new file mode 100644
index 0000000..350086f
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/test-java/DatabaseInit_java.vm
@@ -0,0 +1,68 @@
+#parse("/include/java_header.vm")
+##------------------------------------------------------
+#set( $entityNames = [] )
+#foreach( $entity in $model.allEntites )
+#if ( ! $entity.isJoinEntity() )
+#set($_ = $entityNames.add( $entity.name ) )
+#end
+#end
+##------------------------------------------------------
+package ${target.javaPackageFromFolder($TEST_SRC)};
+
+import javax.persistence.EntityManager;
+
+#foreach( $entityName in $entityNames )
+## import ${ROOT_PKG}.jpa.data.${entityName}Data;
+import ${ROOT_PKG}.entities.${entityName}JpaTest;
+#end
+
+/**
+ * Database initialization before unit tests
+ *
+ * @author Telosys
+ *
+ */
+public class DatabaseInit {
+
+ /**
+ * Set database initial state
+ * @param em
+ */
+ public static void initializeTablesData(EntityManager em) {
+
+ // Disable referential integrity
+ execNativeQuery(em, "SET REFERENTIAL_INTEGRITY FALSE");
+
+ // Initialize each table with one entity
+#foreach( $entityName in $entityNames )
+ initTableWithEntity(em, ${entityName}JpaTest.getInitEntity());
+#end
+
+ // Enable referential integrity
+ execNativeQuery(em, "SET REFERENTIAL_INTEGRITY TRUE");
+ }
+
+ private static void execNativeQuery(EntityManager em, String sql) {
+ em.getTransaction().begin();
+ em.createNativeQuery(sql).executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private static void initTableWithEntity(EntityManager em, Object entity) {
+ execQuery(em, "DELETE FROM " + entity.getClass().getSimpleName());
+ initEntity(em, entity);
+ }
+
+ private static void execQuery(EntityManager em, String sql) {
+ em.getTransaction().begin();
+ em.createQuery(sql).executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private static void initEntity(EntityManager em, Object entity) {
+ em.getTransaction().begin();
+ em.merge(entity);
+ em.getTransaction().commit();
+ }
+
+}
\ No newline at end of file
diff --git a/TelosysTools/templates/infinimotion/test-java/JpaTest_java.vm b/TelosysTools/templates/infinimotion/test-java/JpaTest_java.vm
new file mode 100644
index 0000000..f77fea8
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/test-java/JpaTest_java.vm
@@ -0,0 +1,247 @@
+#parse("/include/java_header.vm")
+##------------------------------------------------------
+package ${target.javaPackageFromFolder($TEST_SRC)};
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+/**
+ * Generic abstract class for JPA JUnit test cases
+ *
+ * @author Telosys
+ */
+public abstract class JpaTest {
+
+ /**
+ * JPA Persistence Unit name for unit tests
+ * Must be the same as in "src/test/resources/META-INF/persistence.xml"
+ */
+ private static final String PERSISTENCE_UNIT_NAME = "h2-test";
+
+ private static final boolean LOG_FLAG = true;
+
+ protected static EntityManagerFactory emf;
+
+ /**
+ * Prints a log message
+ * @param msg
+ */
+ protected static void log(String msg) {
+ if (LOG_FLAG) {
+ System.out.println("[LOG-TEST] " + msg);
+ System.out.flush();
+ }
+ }
+
+ private EntityManager createEntityManager() {
+ log(" createEntityManager()...");
+ return emf.createEntityManager();
+ }
+
+ private void closeEntityManager(EntityManager em) {
+ log(" closeEntityManager(em)...");
+ em.clear();
+ em.close();
+ }
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ log("----- BeforeClass : Initializing JPA env...");
+ // All database tables are created before each test case class
+ // thanks to 'persistence.xml' property "hibernate.hbm2ddl.auto" set to "create"
+ emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ log("----- AfterClass : Closing JPA env...");
+ if ( emf != null ) {
+ emf.close();
+ }
+ }
+
+ @Before
+ public void setUpBeforeTest() throws Exception {
+ log("--- Before test : setUpBeforeTest()...");
+ EntityManager em = createEntityManager();
+ log(" DatabaseInit.init(em)...");
+ DatabaseInit.initializeTablesData(em);
+ closeEntityManager(em);
+ log(" Database initialized and ready for test.");
+ }
+
+ @After
+ public void tearDownAfterTest() throws Exception {
+ log("--- After test : tearDownAfterTest()...");
+ }
+
+ /**
+ * Call em.find(entityClass, pk)
+ * @param
+ * @param entityClass
+ * @param pk
+ * @return
+ */
+ protected T find(Class entityClass, Object pk) {
+ log("find(" + entityClass.getSimpleName() + ", " + pk +")");
+ return findAndPossiblyRefresh(entityClass, pk, false);
+ }
+
+ /**
+ * Call em.find(entityClass, pk) and call em.refresh(entity) if entity found
+ * @param
+ * @param entityClass
+ * @param pk
+ * @return
+ */
+ protected T findAndRefresh(Class entityClass, Object pk) {
+ log("findAndRefresh(" + entityClass.getSimpleName() + ", " + pk +")");
+ return findAndPossiblyRefresh(entityClass, pk, true);
+ }
+
+ /**
+ * Calls find then call refresh if flag is true
+ * @param
+ * @param entityClass
+ * @param pk
+ * @param refreshFlag
+ * @return
+ */
+ private T findAndPossiblyRefresh(Class entityClass, Object pk, boolean refreshFlag) {
+ EntityManager em = createEntityManager();
+ T entity = em.find(entityClass, pk);
+ if ( entity != null ) {
+ log(" em.find(entity,pk) : found ");
+ if ( refreshFlag ) {
+ log(" em.refresh(entity)");
+ em.refresh(entity); // Useful to refresh links => SQL SELECT
+ }
+ } else {
+ log(" em.find(entity,pk) : not found ");
+ }
+ closeEntityManager(em);
+ return entity ;
+ }
+
+ /**
+ * Call em.persist(entity) in a transaction
+ * @param entity
+ */
+ protected void persist(Object entity) {
+ log("persist("+entity+")");
+ persistAndPossiblyRefresh(entity, false);
+ }
+
+ /**
+ * Call em.persist(entity) in a transaction then call em.refresh(entity)
+ * @param entity
+ */
+ protected void persistAndRefresh(Object entity) {
+ log("persistAndRefresh("+entity+")");
+ persistAndPossiblyRefresh(entity, true);
+ }
+
+ /**
+ * Calls persist then call refresh if flag is true
+ * @param entity
+ * @param refreshFlag
+ */
+ private void persistAndPossiblyRefresh(Object entity, boolean refreshFlag) {
+ log("persistAndRefresh("+entity+")");
+ EntityManager em = createEntityManager();
+ log(" em.getTransaction().begin()");
+ em.getTransaction().begin();
+ log(" em.persist(entity)");
+ em.persist(entity);
+ log(" em.getTransaction().commit()");
+ em.getTransaction().commit();
+ // Refresh ?
+ if ( refreshFlag ) {
+ log(" em.refresh("+entity+")");
+ em.refresh(entity); // Useful to refresh links => SQL SELECT
+ }
+ closeEntityManager(em);
+ }
+
+ /**
+ * Calls em.merge(entity) in a transaction
+ * @param entity
+ * @return the managed entity (object returned by JPA merge)
+ */
+ protected Object merge(Object entity) {
+ log("merge("+entity+")");
+ return mergeAndPossiblyRefresh(entity, false);
+ }
+
+ /**
+ * Calls em.merge(entity) in a transaction and refresh the managed entity
+ * @param entity
+ * @return the managed entity (object returned by JPA merge and refreshed)
+ */
+ protected Object mergeAndRefresh(Object entity) {
+ log("mergeAndRefresh("+entity+")");
+ return mergeAndPossiblyRefresh(entity, false);
+ }
+
+ /**
+ * Call merge then call refresh if flag is true
+ * @param entity
+ * @param refreshFlag
+ * @return
+ */
+ private Object mergeAndPossiblyRefresh(Object entity, boolean refreshFlag) {
+ EntityManager em = createEntityManager();
+ // Merge
+ log(" em.getTransaction().begin()");
+ em.getTransaction().begin();
+ log(" em.merge("+entity+")");
+ Object managedEntity = em.merge(entity);
+ log(" em.getTransaction().commit()");
+ em.getTransaction().commit();
+ // Refresh ?
+ if ( refreshFlag ) {
+ log(" em.refresh("+managedEntity+")");
+ em.refresh(managedEntity); // Useful to refresh links => SQL SELECT
+ }
+ closeEntityManager(em);
+ return managedEntity;
+ }
+
+ /**
+ * Try to find an entity and call em.remove(entity) in a transaction
+ * @param
+ * @param entityClass
+ * @param pk
+ * @return true if found and removed, else false
+ */
+ protected boolean findAndRemove(Class entityClass, Object pk) {
+ boolean removed = false;
+ log("findAndRemove(" + entityClass.getSimpleName() + ", " + pk +")");
+ EntityManager em = createEntityManager();
+ log(" em.find(entity,pk) ");
+ T entity = em.find(entityClass, pk);
+ if ( entity != null ) {
+ log(" found ");
+ log(" em.getTransaction().begin()");
+ em.getTransaction().begin();
+ log(" em.remove(entity)");
+ em.remove(entity);
+ log(" em.getTransaction().commit()");
+ em.getTransaction().commit();
+ removed = true;
+ }
+ else {
+ log(" not found ");
+ removed = false;
+ }
+ closeEntityManager(em);
+ return removed;
+ }
+
+}
diff --git a/TelosysTools/templates/infinimotion/test-java/XxxData_java.vm b/TelosysTools/templates/infinimotion/test-java/XxxData_java.vm
new file mode 100644
index 0000000..afaa7ab
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/test-java/XxxData_java.vm
@@ -0,0 +1,40 @@
+## --------------------------------------------------
+#if ( $entity.isJoinEntity() )
+#cancel("No test class for join entity")
+#end
+## --------------------------------------------------
+#parse("include/init_var_entity.vm")
+#parse("/include/java_header.vm")
+#set( $values = $fn.buildValues($entity.attributes, 1) )
+##------------------------------------------------------
+package ${target.javaPackageFromFolder($TEST_SRC)};
+
+import javax.persistence.EntityManager;
+
+import ${ROOT_PKG}.entities.${entity.name};
+
+public class ${entity.name}Data {
+
+ private static ${entity.name} entity ;
+
+ public static void init(EntityManager em) {
+ // new entity instance
+ ${entity.name} newEntity = new ${entity.name}();
+#foreach( $attribute in $entity.attributes )
+## #if ( $attribute.isNotNull() )
+## newEntity.${attribute.setter}( $values.getValue($attribute.name) ) ;
+## #end
+ newEntity.${attribute.setter}( $values.getValue($attribute.name) ) ;
+#end
+
+ // save entity in database
+ em.getTransaction().begin();
+ ${entity.name} managedEntity = (${entity.name}) em.merge(newEntity);
+ em.getTransaction().commit();
+ entity = managedEntity;
+ }
+
+ public static ${entity.name} getEntity() {
+ return entity;
+ }
+}
diff --git a/TelosysTools/templates/infinimotion/test-java/XxxJpaTest_java.vm b/TelosysTools/templates/infinimotion/test-java/XxxJpaTest_java.vm
new file mode 100644
index 0000000..93c315b
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/test-java/XxxJpaTest_java.vm
@@ -0,0 +1,134 @@
+## --------------------------------------------------
+#if ( $entity.isJoinEntity() )
+#cancel("No test class for join entity")
+#end
+## --------------------------------------------------
+#parse("include/init_var_entity.vm")
+#parse("/include/java_header.vm")
+##------------------------------------------------------
+package ${target.javaPackageFromFolder($TEST_SRC)};
+
+import static junit.framework.TestCase.assertNotNull;
+
+## import ${ROOT_PKG}.jpa.tools.JpaTest;
+import ${ROOT_PKG}.entities.tooling.JpaTest;
+import org.junit.Test;
+
+## macro to define referenced value for the given attribute
+#macro( setRefValue $attrib )
+#foreach( $fkPart in $attrib.fkParts )
+#if ( $foreach.count == 1 )
+## #set( $refEntity = $model.getEntityByClassName($fkPart.referencedEntityName) )
+## #set( $refAttribute = $refEntity.getAttributeByName($fkPart.referencedAttributeName) )
+## #set( $refValue = "${refEntity.name}JpaTest.getInitEntity().${refAttribute.getter}()" )
+## new (for test)
+#set( $n = $attrib.fkPartsCount )
+#set( $e = $fkPart.referencedEntity )
+#set( $a = $fkPart.referencedAttribute )
+##
+#set( $refValue = "${fkPart.referencedEntityName}JpaTest.getInitEntity().${fkPart.referencedAttribute.getter}()" )
+#end
+#end
+#end
+##
+#set( $values1 = $fn.buildValues($entity.attributes, 1) )
+#set( $values2 = $fn.buildValues($entity.attributes, 2) )
+##
+public class ${entity.name}JpaTest extends JpaTest {
+
+ public static ${entity.name} getInitEntity() {
+#buildEntity($values1)
+ }
+
+ private ${entity.name} createEntity() {
+#buildEntity($values2)
+ }
+
+#macro( buildEntity $argValues )
+ ${entity.name} entity = new ${entity.name}();
+#foreach( $attribute in $entity.attributes )
+#if ( $attribute.isFK() )
+#setRefValue ( $attribute )
+ entity.${attribute.setter}( $refValue ) ;
+#else
+#if ( ! $attribute.isAutoIncremented() )
+ entity.${attribute.setter}( $argValues.getValue($attribute.name) ) ;
+#else
+ // $attribute.name is auto-incremented => do not set
+#end
+#end
+#end
+ return entity;
+#end
+
+ private Object getEntityKey(${entity.name} entity) {
+#if ( $entity.hasCompositePrimaryKey() )
+ return new ${jpaEntityIdClass}( $fn.argumentsListWithGetter("entity", $entity.keyAttributes) );
+#else
+ return entity.${entity.keyAttribute.getter}();
+#end
+ }
+
+ @Test
+ public void testFind() {
+#if ( $entity.hasGeneratedKey() )
+ // NB: this entity has an GENERATED PRIMARY KEY
+ // Cannot use a generic test with this kind of PK
+ // Create a specific test for this case
+#else
+ ${entity.name} e = find(${entity.name}.class, getEntityKey(getInitEntity()) );
+ assertNotNull(e);
+#end
+ }
+
+ @Test
+ public void testPersistFind() {
+#if ( $entity.hasGeneratedKey() )
+ // NB: this entity has an GENERATED PRIMARY KEY
+ // Cannot use a generic test with this kind of PK
+ // Create a specific test for this case
+#else
+ ${entity.name} entity = createEntity();
+ Object key = getEntityKey(entity);
+
+ // if entity doesn't exist yet
+ if ( find(${entity.name}.class, key) == null ) {
+
+ // Create with 'persist'
+ persistAndRefresh(entity);
+
+ // Find
+ ${entity.name} entity2 = find(${entity.name}.class, key);
+ assertNotNull(entity2);
+
+ // Remove (use only if no risk of referential integrity constraint violation)
+ // findAndRemove(${entity.name}.class, key);
+ // assertNull(find(${entity.name}.class, key));
+ }
+#end
+ }
+
+ @Test
+ public void testMergeFind() {
+#if ( $entity.hasGeneratedKey() )
+ // NB: this entity has an GENERATED PRIMARY KEY
+ // Cannot use a generic test with this kind of PK
+ // Create a specific test for this case
+#else
+ ${entity.name} entity = createEntity();
+ Object key = getEntityKey(entity);
+
+ // Create or update with 'merge'
+ mergeAndRefresh(entity);
+
+ // Find
+ ${entity.name} entity2 = find(${entity.name}.class, key);
+ assertNotNull(entity2);
+
+ // Remove (use only if no risk of referential integrity constraint violation)
+ // findAndRemove(${entity.name}.class, key);
+ // assertNull(find(${entity.name}.class, key));
+#end
+ }
+
+}
diff --git a/TelosysTools/templates/infinimotion/test-resources/persistence_xml.vm b/TelosysTools/templates/infinimotion/test-resources/persistence_xml.vm
new file mode 100644
index 0000000..ef8631d
--- /dev/null
+++ b/TelosysTools/templates/infinimotion/test-resources/persistence_xml.vm
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+
+
+
+#set( $DB_SCHEMA_NAME = "TO_BE_DEFINED" )
+#foreach( $entity in $selectedEntities )
+ ${ROOT_PKG}.entities.${entity.name}
+## Just keep the schema of the last entity
+#set( $DB_SCHEMA_NAME = $entity.databaseSchema )
+#end
+
+## Schema name is determined from entities
+#if ( ${DB_SCHEMA_NAME} != "" )
+#set( $INIT_DB = ";INIT=CREATE SCHEMA IF NOT EXISTS ${DB_SCHEMA_NAME}" )
+#else
+#set( $INIT_DB = "" )
+
+#end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file