Compare commits
	
		
			49 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a82c3e725d | |||
| 08124f212a | |||
| 631999e135 | |||
| 7674d9a299 | |||
| 9cd71ab601 | |||
| 4cb8c84312 | |||
| 5acdbfb0c7 | |||
| d35c83fcbf | |||
| 0fe769a203 | |||
| dbe1b469f6 | |||
| 875b4b313b | |||
| 15a7814a3b | |||
| 530d254bf2 | |||
| e1d9da70c8 | |||
| c13f910620 | |||
| 6944331761 | |||
| 151aa498e5 | |||
| db6a20fa02 | |||
| 8e913b54ad | |||
| 092bef5a7b | |||
| e5d75bc97b | |||
| 7c217716c9 | |||
| 526f902eae | |||
| 42ac2f3056 | |||
| 389e4138c3 | |||
| 6584022861 | |||
| 41fb181545 | |||
| 56609e4f59 | |||
| e0b7ed1e1e | |||
| 48c32a3744 | |||
| fc521d2287 | |||
| 15125e2d6d | |||
| 6f1dd991c5 | |||
| 009831f5db | |||
| 1bcdb1df8c | |||
| 7ae948bb79 | |||
| 29402fc27e | |||
| eca28292d5 | |||
| aef4cdabc3 | |||
| 04114aa0cf | |||
| 575102fbfa | |||
| 19fa13849e | |||
| 9ffebf1d1d | |||
| e35a1ae879 | |||
| 9c9cf85f92 | |||
| 1a2302f548 | |||
| 808784889b | |||
| f394254f38 | |||
| 0574d5da82 | 
							
								
								
									
										21
									
								
								.classpath
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								.classpath
									
									
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <classpath> | <classpath> | ||||||
| 	<classpathentry including="**/*.java" kind="src" output="out/maven/classes" path="src"> | 	<classpathentry including="**/*.java" kind="src" output="target/classes" path="src"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="optional" value="true"/> | 			<attribute name="optional" value="true"/> | ||||||
| 			<attribute name="maven.pomderived" value="true"/> | 			<attribute name="maven.pomderived" value="true"/> | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="src" output="out/maven/test-classes" path="test/src"> | 	<classpathentry kind="src" output="target/test-classes" path="test/src"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="test" value="true"/> | 			<attribute name="test" value="true"/> | ||||||
| 			<attribute name="optional" value="true"/> | 			<attribute name="optional" value="true"/> | ||||||
| @@ -18,17 +18,28 @@ | |||||||
| 			<attribute name="maven.pomderived" value="true"/> | 			<attribute name="maven.pomderived" value="true"/> | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry excluding="**" kind="src" output="out/maven/test-classes" path="test/resources"> | 	<classpathentry excluding="**" kind="src" output="target/test-classes" path="test/resources"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="test" value="true"/> | 			<attribute name="test" value="true"/> | ||||||
| 			<attribute name="maven.pomderived" value="true"/> | 			<attribute name="maven.pomderived" value="true"/> | ||||||
| 			<attribute name="optional" value="true"/> | 			<attribute name="optional" value="true"/> | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"> | 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="maven.pomderived" value="true"/> | 			<attribute name="maven.pomderived" value="true"/> | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="output" path="out/maven/classes"/> | 	<classpathentry kind="src" path="target/generated-sources/annotations"> | ||||||
|  | 		<attributes> | ||||||
|  | 			<attribute name="optional" value="true"/> | ||||||
|  | 		</attributes> | ||||||
|  | 	</classpathentry> | ||||||
|  | 	<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations"> | ||||||
|  | 		<attributes> | ||||||
|  | 			<attribute name="test" value="true"/> | ||||||
|  | 			<attribute name="optional" value="true"/> | ||||||
|  | 		</attributes> | ||||||
|  | 	</classpathentry> | ||||||
|  | 	<classpathentry kind="output" path="target/classes"/> | ||||||
| </classpath> | </classpath> | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.island/release.bash
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								.island/release.bash
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | mvn versions:set -DnewVersion=$(cat version.txt) | ||||||
|  |  | ||||||
| @@ -84,7 +84,6 @@ Reformat XML file like the pom.xml | |||||||
| XMLLINT_INDENT="	" xmllint  --format "back/pom.xml" -o "back/pom.xml" | XMLLINT_INDENT="	" xmllint  --format "back/pom.xml" -o "back/pom.xml" | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
| Enable the pre-commit checker | Enable the pre-commit checker | ||||||
| ----------------------------- | ----------------------------- | ||||||
|  |  | ||||||
| @@ -94,6 +93,8 @@ Enable the pre-commit checker | |||||||
|  |  | ||||||
| > **_Note_**: You can change the code in `.git/hooks/pre-commit` by replacing `formatter:verify` with `formatter:format` to auto format the code @ every commit | > **_Note_**: You can change the code in `.git/hooks/pre-commit` by replacing `formatter:verify` with `formatter:format` to auto format the code @ every commit | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Add Gitea in the dependency for the registry: | Add Gitea in the dependency for the registry: | ||||||
| ============================================= | ============================================= | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -3,7 +3,7 @@ | |||||||
| 	<modelVersion>4.0.0</modelVersion> | 	<modelVersion>4.0.0</modelVersion> | ||||||
| 	<groupId>kangaroo-and-rabbit</groupId> | 	<groupId>kangaroo-and-rabbit</groupId> | ||||||
| 	<artifactId>archidata</artifactId> | 	<artifactId>archidata</artifactId> | ||||||
| 	<version>0.6.0</version> | 	<version>0.7.3</version> | ||||||
| 	<properties> | 	<properties> | ||||||
| 		<maven.compiler.version>3.1</maven.compiler.version> | 		<maven.compiler.version>3.1</maven.compiler.version> | ||||||
| 		<maven.compiler.source>21</maven.compiler.source> | 		<maven.compiler.source>21</maven.compiler.source> | ||||||
| @@ -107,8 +107,19 @@ | |||||||
| 		<dependency> | 		<dependency> | ||||||
| 			<groupId>com.fasterxml.jackson.core</groupId> | 			<groupId>com.fasterxml.jackson.core</groupId> | ||||||
| 			<artifactId>jackson-databind</artifactId> | 			<artifactId>jackson-databind</artifactId> | ||||||
| 			<version>2.16.0</version> | 			<version>2.16.1</version> | ||||||
| 		</dependency> | 		</dependency> | ||||||
|  | 		<dependency> | ||||||
|  | 			<groupId>com.fasterxml.jackson.dataformat</groupId> | ||||||
|  | 			<artifactId>jackson-dataformat-csv</artifactId> | ||||||
|  | 			<version>2.16.1</version> | ||||||
|  | 		</dependency> | ||||||
|  | 		<dependency> | ||||||
|  | 			<groupId>com.fasterxml.jackson.datatype</groupId> | ||||||
|  | 			<artifactId>jackson-datatype-jsr310</artifactId> | ||||||
|  | 			<version>2.16.1</version> | ||||||
|  | 		</dependency> | ||||||
|  |  | ||||||
| 		<dependency> | 		<dependency> | ||||||
| 			<groupId>jakarta.servlet</groupId> | 			<groupId>jakarta.servlet</groupId> | ||||||
| 			<artifactId>jakarta.servlet-api</artifactId> | 			<artifactId>jakarta.servlet-api</artifactId> | ||||||
| @@ -160,9 +171,25 @@ | |||||||
| 			<version>5.10.1</version> | 			<version>5.10.1</version> | ||||||
| 	        <scope>test</scope> | 	        <scope>test</scope> | ||||||
| 	    </dependency> | 	    </dependency> | ||||||
|  | 	    <dependency> | ||||||
|  | 		    <groupId>net.revelc.code.formatter</groupId> | ||||||
|  | 		    <artifactId>formatter-maven-plugin</artifactId> | ||||||
|  | 		    <version>2.23.0</version> | ||||||
|  | 		</dependency> | ||||||
|  | 		<dependency> | ||||||
|  | 		    <groupId>org.apache.maven.plugins</groupId> | ||||||
|  | 		    <artifactId>maven-checkstyle-plugin</artifactId> | ||||||
|  | 		    <version>3.3.1</version> | ||||||
|  | 		</dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
|  |  | ||||||
| 	<build> | 	<build> | ||||||
| 		<sourceDirectory>src</sourceDirectory> | 		<sourceDirectory>src</sourceDirectory> | ||||||
|  | 		<resources> | ||||||
|  | 			<resource> | ||||||
|  | 				<directory>${basedir}/src/resources</directory> | ||||||
|  | 			</resource> | ||||||
|  | 		</resources> | ||||||
| 		<testSourceDirectory>test/src</testSourceDirectory> | 		<testSourceDirectory>test/src</testSourceDirectory> | ||||||
| 		<testResources> | 		<testResources> | ||||||
| 			<testResource> | 			<testResource> | ||||||
| @@ -241,7 +268,7 @@ | |||||||
| 			<plugin> | 			<plugin> | ||||||
| 				<groupId>org.apache.maven.plugins</groupId> | 				<groupId>org.apache.maven.plugins</groupId> | ||||||
| 				<artifactId>maven-checkstyle-plugin</artifactId> | 				<artifactId>maven-checkstyle-plugin</artifactId> | ||||||
| 				<version>3.1.0</version> | 		    	<version>3.3.1</version> | ||||||
| 				<configuration> | 				<configuration> | ||||||
| 					<configLocation>CheckStyle.xml</configLocation> | 					<configLocation>CheckStyle.xml</configLocation> | ||||||
| 					<consoleOutput>true</consoleOutput> | 					<consoleOutput>true</consoleOutput> | ||||||
| @@ -253,7 +280,7 @@ | |||||||
| 			<plugin> | 			<plugin> | ||||||
| 				<groupId>net.revelc.code.formatter</groupId> | 				<groupId>net.revelc.code.formatter</groupId> | ||||||
| 				<artifactId>formatter-maven-plugin</artifactId> | 				<artifactId>formatter-maven-plugin</artifactId> | ||||||
| 				<version>2.12.2</version> | 		    	<version>2.23.0</version> | ||||||
| 				<configuration> | 				<configuration> | ||||||
| 					<encoding>UTF-8</encoding> | 					<encoding>UTF-8</encoding> | ||||||
| 					<lineEnding>LF</lineEnding> | 					<lineEnding>LF</lineEnding> | ||||||
|   | |||||||
| @@ -5,6 +5,9 @@ import java.sql.PreparedStatement; | |||||||
| import java.sql.SQLException; | import java.sql.SQLException; | ||||||
|  |  | ||||||
| import org.kar.archidata.dataAccess.DataAccess; | import org.kar.archidata.dataAccess.DataAccess; | ||||||
|  | import org.kar.archidata.dataAccess.QueryOption; | ||||||
|  | import org.kar.archidata.dataAccess.QueryOptions; | ||||||
|  | import org.kar.archidata.dataAccess.options.DBInterfaceOption; | ||||||
| import org.kar.archidata.db.DBEntry; | import org.kar.archidata.db.DBEntry; | ||||||
| import org.kar.archidata.model.User; | import org.kar.archidata.model.User; | ||||||
|  |  | ||||||
| @@ -12,21 +15,22 @@ public class UserDB { | |||||||
|  |  | ||||||
| 	public UserDB() {} | 	public UserDB() {} | ||||||
|  |  | ||||||
| 	public static User getUsers(final long userId) throws Exception { | 	public static User getUsers(final long userId, QueryOption... option) throws Exception { | ||||||
| 		return DataAccess.get(User.class, userId); | 		return DataAccess.get(User.class, userId, option); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static User getUserOrCreate(final long userId, final String userLogin) throws Exception { | 	public static User getUserOrCreate(final long userId, final String userLogin, QueryOption... option) throws Exception { | ||||||
| 		final User user = getUsers(userId); | 		final User user = getUsers(userId); | ||||||
| 		if (user != null) { | 		if (user != null) { | ||||||
| 			return user; | 			return user; | ||||||
| 		} | 		} | ||||||
| 		createUsersInfoFromOAuth(userId, userLogin); | 		createUsersInfoFromOAuth(userId, userLogin, option); | ||||||
| 		return getUsers(userId); | 		return getUsers(userId); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private static void createUsersInfoFromOAuth(final long userId, final String login) throws IOException { | 	private static void createUsersInfoFromOAuth(final long userId, final String login, QueryOption... option) throws IOException { | ||||||
| 		final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		QueryOptions options = new QueryOptions(option); | ||||||
|  | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')"; | 		final String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')"; | ||||||
| 		try { | 		try { | ||||||
| 			final PreparedStatement ps = entry.connection.prepareStatement(query); | 			final PreparedStatement ps = entry.connection.prepareStatement(query); | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ import jakarta.validation.constraints.Min; | |||||||
| import jakarta.validation.constraints.NotNull; | import jakarta.validation.constraints.NotNull; | ||||||
| import jakarta.validation.constraints.Pattern; | import jakarta.validation.constraints.Pattern; | ||||||
| import jakarta.validation.constraints.Size; | import jakarta.validation.constraints.Size; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
| public class AnnotationTools { | public class AnnotationTools { | ||||||
| 	static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class); | 	static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class); | ||||||
| @@ -52,7 +53,40 @@ public class AnnotationTools { | |||||||
| 		return tmp; | 		return tmp; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static String getSchemedescription(final Field element) throws Exception { | 	public static boolean getSchemaReadOnly(final Field element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		if (annotation.length > 1) { | ||||||
|  | 			throw new Exception("Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName()); | ||||||
|  | 		} | ||||||
|  | 		return ((Schema) annotation[0]).readOnly(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String getSchemaExample(final Class<?> element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		if (annotation.length > 1) { | ||||||
|  | 			throw new Exception("Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName()); | ||||||
|  | 		} | ||||||
|  | 		return ((Schema) annotation[0]).example(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String getSchemaDescription(final Class<?> element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		if (annotation.length > 1) { | ||||||
|  | 			throw new Exception("Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName()); | ||||||
|  | 		} | ||||||
|  | 		return ((Schema) annotation[0]).description(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String getSchemaDescription(final Field element) throws Exception { | ||||||
| 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); | ||||||
| 		if (annotation.length == 0) { | 		if (annotation.length == 0) { | ||||||
| 			return null; | 			return null; | ||||||
| @@ -66,7 +100,7 @@ public class AnnotationTools { | |||||||
| 	public static String getComment(final Field element) throws Exception { | 	public static String getComment(final Field element) throws Exception { | ||||||
| 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataComment.class); | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataComment.class); | ||||||
| 		if (annotation.length == 0) { | 		if (annotation.length == 0) { | ||||||
| 			return getSchemedescription(element); | 			return getSchemaDescription(element); | ||||||
| 		} | 		} | ||||||
| 		if (annotation.length > 1) { | 		if (annotation.length > 1) { | ||||||
| 			throw new Exception("Must not have more than 1 element @DataComment on " + element.getClass().getCanonicalName()); | 			throw new Exception("Must not have more than 1 element @DataComment on " + element.getClass().getCanonicalName()); | ||||||
| @@ -75,14 +109,14 @@ public class AnnotationTools { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static String getDefault(final Field element) throws Exception { | 	public static String getDefault(final Field element) throws Exception { | ||||||
| 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataDefault.class); | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(DefaultValue.class); | ||||||
| 		if (annotation.length == 0) { | 		if (annotation.length == 0) { | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
| 		if (annotation.length > 1) { | 		if (annotation.length > 1) { | ||||||
| 			throw new Exception("Must not have more than 1 element @DataDefault on " + element.getClass().getCanonicalName()); | 			throw new Exception("Must not have more than 1 element @DataDefault on " + element.getClass().getCanonicalName()); | ||||||
| 		} | 		} | ||||||
| 		return ((DataDefault) annotation[0]).value(); | 		return ((DefaultValue) annotation[0]).value(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static ManyToOne getManyToOne(final Field element) throws Exception { | 	public static ManyToOne getManyToOne(final Field element) throws Exception { | ||||||
| @@ -364,4 +398,17 @@ public class AnnotationTools { | |||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public static Field getFieldNamed(final Class<?> clazz, final String name) throws Exception { | ||||||
|  | 		for (final Field field : clazz.getFields()) { | ||||||
|  | 			// static field is only for internal global declaration ==> remove it .. | ||||||
|  | 			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (AnnotationTools.getFieldName(field).equals(name)) { | ||||||
|  | 				return field; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return null; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								src/org/kar/archidata/annotation/AsyncType.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/org/kar/archidata/annotation/AsyncType.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | package org.kar.archidata.annotation; | ||||||
|  |  | ||||||
|  | import java.lang.annotation.ElementType; | ||||||
|  | import java.lang.annotation.Retention; | ||||||
|  | import java.lang.annotation.RetentionPolicy; | ||||||
|  | import java.lang.annotation.Target; | ||||||
|  |  | ||||||
|  | /** In case of the update parameter with String input to detect null element. */ | ||||||
|  | @Target({ ElementType.PARAMETER, ElementType.METHOD }) | ||||||
|  | @Retention(RetentionPolicy.RUNTIME) | ||||||
|  | public @interface AsyncType { | ||||||
|  | 	Class<?> value(); | ||||||
|  | } | ||||||
| @@ -12,4 +12,6 @@ import org.kar.archidata.dataAccess.options.CheckFunctionVoid; | |||||||
| @Retention(RetentionPolicy.RUNTIME) | @Retention(RetentionPolicy.RUNTIME) | ||||||
| public @interface DataJson { | public @interface DataJson { | ||||||
| 	Class<? extends CheckFunctionInterface> checker() default CheckFunctionVoid.class; | 	Class<? extends CheckFunctionInterface> checker() default CheckFunctionVoid.class; | ||||||
|  |  | ||||||
|  | 	Class<?> targetEntity() default Void.class; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,10 +5,8 @@ import java.lang.annotation.Retention; | |||||||
| import java.lang.annotation.RetentionPolicy; | import java.lang.annotation.RetentionPolicy; | ||||||
| import java.lang.annotation.Target; | import java.lang.annotation.Target; | ||||||
| 
 | 
 | ||||||
| @Target({ ElementType.TYPE, ElementType.FIELD }) | /** In case of the update parameter with String input to detect null element. */ | ||||||
|  | @Target({ ElementType.PARAMETER, ElementType.METHOD }) | ||||||
| @Retention(RetentionPolicy.RUNTIME) | @Retention(RetentionPolicy.RUNTIME) | ||||||
| public @interface DataDefault { | public @interface TypeScriptProgress { | ||||||
| 
 |  | ||||||
| 	String value(); |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
| @@ -16,6 +16,7 @@ import java.nio.file.StandardCopyOption; | |||||||
| import java.security.MessageDigest; | import java.security.MessageDigest; | ||||||
| import java.security.NoSuchAlgorithmException; | import java.security.NoSuchAlgorithmException; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| import javax.imageio.ImageIO; | import javax.imageio.ImageIO; | ||||||
|  |  | ||||||
| @@ -56,7 +57,7 @@ import jakarta.ws.rs.core.StreamingOutput; | |||||||
| @Path("/data") | @Path("/data") | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| public class DataResource { | public class DataResource { | ||||||
| 	private static final Logger LOGGER = LoggerFactory.getLogger(MediaType.class); | 	private static final Logger LOGGER = LoggerFactory.getLogger(DataResource.class); | ||||||
| 	private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks | 	private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks | ||||||
| 	private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks | 	private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks | ||||||
| 	/** Upload some datas */ | 	/** Upload some datas */ | ||||||
| @@ -83,7 +84,7 @@ public class DataResource { | |||||||
| 		return filePath; | 		return filePath; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static String getFileData(final long tmpFolderId) { | 	public static String getFileDataOld(final long tmpFolderId) { | ||||||
| 		final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; | 		final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; | ||||||
| 		try { | 		try { | ||||||
| 			createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); | 			createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); | ||||||
| @@ -93,6 +94,26 @@ public class DataResource { | |||||||
| 		return filePath; | 		return filePath; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public static String getFileData(final UUID uuid) { | ||||||
|  | 		final String stringUUID = uuid.toString(); | ||||||
|  | 		final String part1 = stringUUID.substring(0, 2); | ||||||
|  | 		final String part2 = stringUUID.substring(2, 4); | ||||||
|  | 		final String part3 = stringUUID.substring(4); | ||||||
|  | 		final String finalPath = part1 + File.separator + part2; | ||||||
|  | 		String filePath = ConfigBaseVariable.getMediaDataFolder() + "_uuid" + File.separator + finalPath + File.separator; | ||||||
|  | 		try { | ||||||
|  | 			createFolder(filePath); | ||||||
|  | 		} catch (final IOException e) { | ||||||
|  | 			e.printStackTrace(); | ||||||
|  | 		} | ||||||
|  | 		filePath += part3; | ||||||
|  | 		return filePath; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String getFileMetaData(final UUID uuid) { | ||||||
|  | 		return getFileData(uuid) + ".json"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public static Data getWithSha512(final String sha512) { | 	public static Data getWithSha512(final String sha512) { | ||||||
| 		LOGGER.info("find sha512 = {}", sha512); | 		LOGGER.info("find sha512 = {}", sha512); | ||||||
| 		try { | 		try { | ||||||
| @@ -137,7 +158,6 @@ public class DataResource { | |||||||
| 		try { | 		try { | ||||||
| 			injectedData = DataAccess.insert(injectedData); | 			injectedData = DataAccess.insert(injectedData); | ||||||
| 		} catch (final Exception e) { | 		} catch (final Exception e) { | ||||||
| 			// TODO Auto-generated catch block |  | ||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
| @@ -149,6 +169,25 @@ public class DataResource { | |||||||
| 		return injectedData; | 		return injectedData; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public static void modeFileOldModelToNewModel(final long id, final UUID uuid) throws IOException { | ||||||
|  | 		String mediaCurentPath = getFileDataOld(id); | ||||||
|  | 		String mediaDestPath = getFileData(uuid); | ||||||
|  | 		LOGGER.info("src = {}", mediaCurentPath); | ||||||
|  | 		LOGGER.info("dst = {}", mediaDestPath); | ||||||
|  | 		if (Files.exists(Paths.get(mediaCurentPath))) { | ||||||
|  | 			LOGGER.info("move: {} ==> {}", mediaCurentPath, mediaDestPath); | ||||||
|  | 			Files.move(Paths.get(mediaCurentPath), Paths.get(mediaDestPath), StandardCopyOption.ATOMIC_MOVE); | ||||||
|  | 		} | ||||||
|  | 		// Move old meta-data... | ||||||
|  | 		mediaCurentPath = mediaCurentPath.substring(mediaCurentPath.length() - 4) + "meta.json"; | ||||||
|  | 		mediaDestPath = mediaCurentPath.substring(mediaDestPath.length() - 4) + "meta.json"; | ||||||
|  | 		if (Files.exists(Paths.get(mediaCurentPath))) { | ||||||
|  | 			LOGGER.info("moveM: {} ==> {}", mediaCurentPath, mediaDestPath); | ||||||
|  | 			Files.move(Paths.get(mediaCurentPath), Paths.get(mediaDestPath), StandardCopyOption.ATOMIC_MOVE); | ||||||
|  | 		} | ||||||
|  | 		LOGGER.info("Move done"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public static String saveTemporaryFile(final InputStream uploadedInputStream, final long idData) { | 	public static String saveTemporaryFile(final InputStream uploadedInputStream, final long idData) { | ||||||
| 		return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData)); | 		return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData)); | ||||||
| 	} | 	} | ||||||
| @@ -207,7 +246,7 @@ public class DataResource { | |||||||
| 		return sb.toString(); | 		return sb.toString(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public Data getSmall(final Long id) { | 	public Data getSmall(final UUID id) { | ||||||
| 		try { | 		try { | ||||||
| 			return DataAccess.get(Data.class, id); | 			return DataAccess.get(Data.class, id); | ||||||
| 		} catch (final Exception e) { | 		} catch (final Exception e) { | ||||||
| @@ -222,7 +261,7 @@ public class DataResource { | |||||||
| 	@Consumes({ MediaType.MULTIPART_FORM_DATA }) | 	@Consumes({ MediaType.MULTIPART_FORM_DATA }) | ||||||
| 	@RolesAllowed("ADMIN") | 	@RolesAllowed("ADMIN") | ||||||
| 	@Operation(description = "Insert a new data in the data environment", tags = "SYSTEM") | 	@Operation(description = "Insert a new data in the data environment", tags = "SYSTEM") | ||||||
| 	public Response uploadFile(@Context final SecurityContext sc, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) { | 	public void uploadFile(@Context final SecurityContext sc, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) { | ||||||
| 		final GenericContext gc = (GenericContext) sc.getUserPrincipal(); | 		final GenericContext gc = (GenericContext) sc.getUserPrincipal(); | ||||||
| 		LOGGER.info("==================================================="); | 		LOGGER.info("==================================================="); | ||||||
| 		LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken)); | 		LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken)); | ||||||
| @@ -236,8 +275,6 @@ public class DataResource { | |||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| 		} | 		} | ||||||
| 		saveFile(fileInputStream, filePath); | 		saveFile(fileInputStream, filePath); | ||||||
| 		return Response.ok("Data uploaded successfully !!").build(); |  | ||||||
| 		// return null; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@GET | 	@GET | ||||||
| @@ -246,17 +283,17 @@ public class DataResource { | |||||||
| 	@RolesAllowed("USER") | 	@RolesAllowed("USER") | ||||||
| 	@Produces(MediaType.APPLICATION_OCTET_STREAM) | 	@Produces(MediaType.APPLICATION_OCTET_STREAM) | ||||||
| 	@Operation(description = "Get back some data from the data environment", tags = "SYSTEM") | 	@Operation(description = "Get back some data from the data environment", tags = "SYSTEM") | ||||||
| 	public Response retriveDataId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range, | 	public Response retrieveDataId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range, | ||||||
| 			@PathParam("id") final Long id) throws Exception { | 			@PathParam("id") final UUID id) throws Exception { | ||||||
| 		final GenericContext gc = (GenericContext) sc.getUserPrincipal(); | 		final GenericContext gc = (GenericContext) sc.getUserPrincipal(); | ||||||
| 		// logger.info("==================================================="); | 		// logger.info("==================================================="); | ||||||
| 		LOGGER.info("== DATA retriveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken)); | 		LOGGER.info("== DATA retrieveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken)); | ||||||
| 		// logger.info("==================================================="); | 		// logger.info("==================================================="); | ||||||
| 		final Data value = getSmall(id); | 		final Data value = getSmall(id); | ||||||
| 		if (value == null) { | 		if (value == null) { | ||||||
| 			Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); | 			Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); | ||||||
| 		} | 		} | ||||||
| 		return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType); | 		return buildStream(getFileData(id), range, value.mimeType); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@GET | 	@GET | ||||||
| @@ -266,17 +303,17 @@ public class DataResource { | |||||||
| 	@Produces(MediaType.APPLICATION_OCTET_STREAM) | 	@Produces(MediaType.APPLICATION_OCTET_STREAM) | ||||||
| 	@Operation(description = "Get a thumbnail of from the data environment (if resize is possible)", tags = "SYSTEM") | 	@Operation(description = "Get a thumbnail of from the data environment (if resize is possible)", tags = "SYSTEM") | ||||||
| 	// @CacheMaxAge(time = 10, unit = TimeUnit.DAYS) | 	// @CacheMaxAge(time = 10, unit = TimeUnit.DAYS) | ||||||
| 	public Response retriveDataThumbnailId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range, | 	public Response retrieveDataThumbnailId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range, | ||||||
| 			@PathParam("id") final Long id) throws Exception { | 			@PathParam("id") final UUID id) throws Exception { | ||||||
| 		// GenericContext gc = (GenericContext) sc.getUserPrincipal(); | 		// GenericContext gc = (GenericContext) sc.getUserPrincipal(); | ||||||
| 		// logger.info("==================================================="); | 		// logger.info("==================================================="); | ||||||
| 		// logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user)); | 		// logger.info("== DATA retrieveDataThumbnailId ? {}", (gc==null?"null":gc.user)); | ||||||
| 		// logger.info("==================================================="); | 		// logger.info("==================================================="); | ||||||
| 		final Data value = getSmall(id); | 		final Data value = getSmall(id); | ||||||
| 		if (value == null) { | 		if (value == null) { | ||||||
| 			return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); | 			return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); | ||||||
| 		} | 		} | ||||||
| 		final String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data"; | 		final String filePathName = getFileData(id); | ||||||
| 		final File inputFile = new File(filePathName); | 		final File inputFile = new File(filePathName); | ||||||
| 		if (!inputFile.exists()) { | 		if (!inputFile.exists()) { | ||||||
| 			return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build(); | 			return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build(); | ||||||
| @@ -318,24 +355,23 @@ public class DataResource { | |||||||
| 		return buildStream(filePathName, range, value.mimeType); | 		return buildStream(filePathName, range, value.mimeType); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// @Secured |  | ||||||
| 	@GET | 	@GET | ||||||
| 	@Path("{id}/{name}") | 	@Path("{id}/{name}") | ||||||
| 	@PermitTokenInURI | 	@PermitTokenInURI | ||||||
| 	@RolesAllowed("USER") | 	@RolesAllowed("USER") | ||||||
| 	@Produces(MediaType.APPLICATION_OCTET_STREAM) | 	@Produces(MediaType.APPLICATION_OCTET_STREAM) | ||||||
| 	@Operation(description = "Get back some data from the data environment (with a beautifull name (permit download with basic name)", tags = "SYSTEM") | 	@Operation(description = "Get back some data from the data environment (with a beautiful name (permit download with basic name)", tags = "SYSTEM") | ||||||
| 	public Response retriveDataFull(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range, | 	public Response retrieveDataFull(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range, | ||||||
| 			@PathParam("id") final Long id, @PathParam("name") final String name) throws Exception { | 			@PathParam("id") final UUID id, @PathParam("name") final String name) throws Exception { | ||||||
| 		final GenericContext gc = (GenericContext) sc.getUserPrincipal(); | 		final GenericContext gc = (GenericContext) sc.getUserPrincipal(); | ||||||
| 		// logger.info("==================================================="); | 		// logger.info("==================================================="); | ||||||
| 		LOGGER.info("== DATA retriveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken)); | 		LOGGER.info("== DATA retrieveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken)); | ||||||
| 		// logger.info("==================================================="); | 		// logger.info("==================================================="); | ||||||
| 		final Data value = getSmall(id); | 		final Data value = getSmall(id); | ||||||
| 		if (value == null) { | 		if (value == null) { | ||||||
| 			Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); | 			Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); | ||||||
| 		} | 		} | ||||||
| 		return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType); | 		return buildStream(getFileData(id), range, value.mimeType); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541 | 	/** Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541 | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ public class FailExceptionCatcher implements ExceptionMapper<FailException> { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Response toResponse(final FailException exception) { | 	public Response toResponse(final FailException exception) { | ||||||
|  | 		LOGGER.warn("Catch FailException:"); | ||||||
| 		final RestErrorResponse ret = build(exception); | 		final RestErrorResponse ret = build(exception); | ||||||
| 		LOGGER.error("Error UUID={}", ret.uuid); | 		LOGGER.error("Error UUID={}", ret.uuid); | ||||||
| 		// Not display backtrace ==> this may be a normal case ... | 		// Not display backtrace ==> this may be a normal case ... | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ public class InputExceptionCatcher implements ExceptionMapper<InputException> { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Response toResponse(final InputException exception) { | 	public Response toResponse(final InputException exception) { | ||||||
|  | 		LOGGER.warn("Catch InputException:"); | ||||||
| 		final RestErrorResponse ret = build(exception); | 		final RestErrorResponse ret = build(exception); | ||||||
| 		LOGGER.error("Error UUID={} ==> '{}'=>'{}'", ret.uuid, exception.missingVariable, exception.getLocalizedMessage()); | 		LOGGER.error("Error UUID={} ==> '{}'=>'{}'", ret.uuid, exception.missingVariable, exception.getLocalizedMessage()); | ||||||
| 		// exception.printStackTrace(); | 		// exception.printStackTrace(); | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ public class JacksonCatcher implements ExceptionMapper<JsonProcessingException> | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private RestErrorResponse build(final Exception exception) { | 	private RestErrorResponse build(final Exception exception) { | ||||||
| 		return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch Unknown Exception", exception.getMessage()); | 		return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch JSON Exception", exception.getMessage()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,19 +3,21 @@ package org.kar.archidata.catcher; | |||||||
| import java.time.Instant; | import java.time.Instant; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.tools.UuidUtils; | ||||||
|  |  | ||||||
| import jakarta.ws.rs.core.Response; | import jakarta.ws.rs.core.Response; | ||||||
|  |  | ||||||
| public class RestErrorResponse { | public class RestErrorResponse { | ||||||
| 	public UUID uuid = UUID.randomUUID(); | 	public UUID uuid = UuidUtils.nextUUID(); | ||||||
|  | 	public String name; // Mandatory for TS generic error | ||||||
|  | 	public String message; // Mandatory for TS generic error | ||||||
| 	public String time; | 	public String time; | ||||||
| 	public String error; |  | ||||||
| 	public String message; |  | ||||||
| 	final public int status; | 	final public int status; | ||||||
| 	final public String statusMessage; | 	final public String statusMessage; | ||||||
|  |  | ||||||
| 	public RestErrorResponse(final Response.Status status, final String time, final String error, final String message) { | 	public RestErrorResponse(final Response.Status status, final String time, final String error, final String message) { | ||||||
| 		this.time = time; | 		this.time = time; | ||||||
| 		this.error = error; | 		this.name = error; | ||||||
| 		this.message = message; | 		this.message = message; | ||||||
| 		this.status = status.getStatusCode(); | 		this.status = status.getStatusCode(); | ||||||
| 		this.statusMessage = status.getReasonPhrase(); | 		this.statusMessage = status.getReasonPhrase(); | ||||||
| @@ -23,13 +25,15 @@ public class RestErrorResponse { | |||||||
|  |  | ||||||
| 	public RestErrorResponse(final Response.Status status, final String error, final String message) { | 	public RestErrorResponse(final Response.Status status, final String error, final String message) { | ||||||
| 		this.time = Instant.now().toString(); | 		this.time = Instant.now().toString(); | ||||||
| 		this.error = error; | 		this.name = error; | ||||||
| 		this.message = message; | 		this.message = message; | ||||||
| 		this.status = status.getStatusCode(); | 		this.status = status.getStatusCode(); | ||||||
| 		this.statusMessage = status.getReasonPhrase(); | 		this.statusMessage = status.getReasonPhrase(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public RestErrorResponse(final Response.Status status) { | 	public RestErrorResponse(final Response.Status status) { | ||||||
|  | 		this.name = "generic"; | ||||||
|  | 		this.message = ""; | ||||||
| 		this.time = Instant.now().toString(); | 		this.time = Instant.now().toString(); | ||||||
| 		this.status = status.getStatusCode(); | 		this.status = status.getStatusCode(); | ||||||
| 		this.statusMessage = status.getReasonPhrase(); | 		this.statusMessage = status.getReasonPhrase(); | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ public class SystemExceptionCatcher implements ExceptionMapper<SystemException> | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Response toResponse(final SystemException exception) { | 	public Response toResponse(final SystemException exception) { | ||||||
|  | 		LOGGER.warn("Catch SystemException:"); | ||||||
| 		final RestErrorResponse ret = build(exception); | 		final RestErrorResponse ret = build(exception); | ||||||
| 		LOGGER.error("Error UUID={}", ret.uuid); | 		LOGGER.error("Error UUID={}", ret.uuid); | ||||||
| 		exception.printStackTrace(); | 		exception.printStackTrace(); | ||||||
|   | |||||||
| @@ -5,20 +5,21 @@ import java.lang.reflect.Constructor; | |||||||
| import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||||
| import java.sql.PreparedStatement; | import java.sql.PreparedStatement; | ||||||
| import java.sql.ResultSet; | import java.sql.ResultSet; | ||||||
|  | import java.sql.ResultSetMetaData; | ||||||
| import java.sql.SQLException; | import java.sql.SQLException; | ||||||
| import java.sql.Statement; | import java.sql.Statement; | ||||||
| import java.sql.Timestamp; | import java.sql.Timestamp; | ||||||
| import java.sql.Types; | import java.sql.Types; | ||||||
|  | import java.time.Instant; | ||||||
| import java.time.LocalDate; | import java.time.LocalDate; | ||||||
| import java.time.LocalTime; | import java.time.LocalTime; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| import org.kar.archidata.GlobalConfiguration; |  | ||||||
| import org.kar.archidata.annotation.AnnotationTools; | import org.kar.archidata.annotation.AnnotationTools; | ||||||
| import org.kar.archidata.annotation.CreationTimestamp; | import org.kar.archidata.annotation.CreationTimestamp; | ||||||
| import org.kar.archidata.annotation.DataDefault; |  | ||||||
| import org.kar.archidata.annotation.UpdateTimestamp; | import org.kar.archidata.annotation.UpdateTimestamp; | ||||||
| import org.kar.archidata.dataAccess.addOn.AddOnDataJson; | import org.kar.archidata.dataAccess.addOn.AddOnDataJson; | ||||||
| import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; | import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; | ||||||
| @@ -26,27 +27,26 @@ import org.kar.archidata.dataAccess.addOn.AddOnManyToOne; | |||||||
| import org.kar.archidata.dataAccess.addOn.AddOnSQLTableExternalForeinKeyAsList; | import org.kar.archidata.dataAccess.addOn.AddOnSQLTableExternalForeinKeyAsList; | ||||||
| import org.kar.archidata.dataAccess.options.CheckFunction; | import org.kar.archidata.dataAccess.options.CheckFunction; | ||||||
| import org.kar.archidata.dataAccess.options.Condition; | import org.kar.archidata.dataAccess.options.Condition; | ||||||
|  | import org.kar.archidata.dataAccess.options.DBInterfaceOption; | ||||||
|  | import org.kar.archidata.dataAccess.options.DBInterfaceRoot; | ||||||
| import org.kar.archidata.dataAccess.options.FilterValue; | import org.kar.archidata.dataAccess.options.FilterValue; | ||||||
| import org.kar.archidata.dataAccess.options.TransmitKey; | import org.kar.archidata.dataAccess.options.TransmitKey; | ||||||
| import org.kar.archidata.db.DBEntry; | import org.kar.archidata.db.DBEntry; | ||||||
| import org.kar.archidata.exception.DataAccessException; | import org.kar.archidata.exception.DataAccessException; | ||||||
| import org.kar.archidata.tools.ConfigBaseVariable; | import org.kar.archidata.tools.ConfigBaseVariable; | ||||||
| import org.kar.archidata.tools.DateTools; | import org.kar.archidata.tools.DateTools; | ||||||
|  | import org.kar.archidata.tools.UuidUtils; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| import com.fasterxml.jackson.databind.JsonNode; | import com.fasterxml.jackson.databind.JsonNode; | ||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  |  | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
| import jakarta.ws.rs.InternalServerErrorException; | import jakarta.ws.rs.InternalServerErrorException; | ||||||
|  |  | ||||||
| /* TODO list: | /* TODO list: | ||||||
|    - useful code to manage external query: List<T> query<T>(class<T> clazz, String query, List<Object> parameters); |  | ||||||
| 		 ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2"); |  | ||||||
| 		 ResultSetMetaData rsmd = rs.getMetaData(); |  | ||||||
| 		 String name = rsmd.getColumnName(1); |  | ||||||
|    - Manage to group of SQL action to permit to commit only at the end. |    - Manage to group of SQL action to permit to commit only at the end. | ||||||
|  |  | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| /** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite | /** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite | ||||||
| @@ -73,7 +73,8 @@ public class DataAccess { | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static boolean isDBExist(final String name) throws InternalServerErrorException { | 	public static boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException { | ||||||
|  | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		if ("sqlite".equals(ConfigBaseVariable.getDBType())) { | 		if ("sqlite".equals(ConfigBaseVariable.getDBType())) { | ||||||
| 			// no base manage in sqLite ... | 			// no base manage in sqLite ... | ||||||
| 			// TODO: check if the file exist or not ... | 			// TODO: check if the file exist or not ... | ||||||
| @@ -81,7 +82,7 @@ public class DataAccess { | |||||||
| 		} | 		} | ||||||
| 		DBEntry entry; | 		DBEntry entry; | ||||||
| 		try { | 		try { | ||||||
| 			entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, true); | 			entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		} catch (final IOException ex) { | 		} catch (final IOException ex) { | ||||||
| 			ex.printStackTrace(); | 			ex.printStackTrace(); | ||||||
| 			LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); | 			LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); | ||||||
| @@ -124,7 +125,7 @@ public class DataAccess { | |||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 		try { | 		try { | ||||||
| 			return 1 == DataAccess.executeSimpleQuerry("CREATE DATABASE `" + name + "`;", true); | 			return 1 == DataAccess.executeSimpleQuerry("CREATE DATABASE `" + name + "`;", new DBInterfaceRoot(true)); | ||||||
| 		} catch (final SQLException | IOException ex) { | 		} catch (final SQLException | IOException ex) { | ||||||
| 			ex.printStackTrace(); | 			ex.printStackTrace(); | ||||||
| 			LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); | 			LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); | ||||||
| @@ -132,7 +133,8 @@ public class DataAccess { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static boolean isTableExist(final String name) throws InternalServerErrorException { | 	public static boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException { | ||||||
|  | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		try { | 		try { | ||||||
| 			String request = ""; | 			String request = ""; | ||||||
| 			if ("sqlite".equals(ConfigBaseVariable.getDBType())) { | 			if ("sqlite".equals(ConfigBaseVariable.getDBType())) { | ||||||
| @@ -143,14 +145,14 @@ public class DataAccess { | |||||||
| 						AND name = ?; | 						AND name = ?; | ||||||
| 						"""; | 						"""; | ||||||
| 				// PreparedStatement ps = entry.connection.prepareStatement("show tables"); | 				// PreparedStatement ps = entry.connection.prepareStatement("show tables"); | ||||||
| 				final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 				final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 				final PreparedStatement ps = entry.connection.prepareStatement(request); | 				final PreparedStatement ps = entry.connection.prepareStatement(request); | ||||||
| 				ps.setString(1, name); | 				ps.setString(1, name); | ||||||
| 				final ResultSet ret = ps.executeQuery(); | 				final ResultSet ret = ps.executeQuery(); | ||||||
| 				final int count = ret.getInt("total"); | 				final int count = ret.getInt("total"); | ||||||
| 				return count == 1; | 				return count == 1; | ||||||
| 			} else { | 			} else { | ||||||
| 				final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 				final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 				// TODO : Maybe connect with a temporary not specified connection interface to a db ... | 				// TODO : Maybe connect with a temporary not specified connection interface to a db ... | ||||||
| 				final PreparedStatement ps = entry.connection.prepareStatement("show tables"); | 				final PreparedStatement ps = entry.connection.prepareStatement("show tables"); | ||||||
| 				final ResultSet rs = ps.executeQuery(); | 				final ResultSet rs = ps.executeQuery(); | ||||||
| @@ -192,7 +194,15 @@ public class DataAccess { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	protected static <T> void setValuedb(final Class<?> type, final T data, final CountInOut iii, final Field field, final PreparedStatement ps) throws Exception { | 	protected static <T> void setValuedb(final Class<?> type, final T data, final CountInOut iii, final Field field, final PreparedStatement ps) throws Exception { | ||||||
| 		if (type == Long.class) { | 		if (type == UUID.class) { | ||||||
|  | 			final Object tmp = field.get(data); | ||||||
|  | 			if (tmp == null) { | ||||||
|  | 				ps.setNull(iii.value, Types.BINARY); | ||||||
|  | 			} else { | ||||||
|  | 				final byte[] dataByte = UuidUtils.asBytes((UUID) tmp); | ||||||
|  | 				ps.setBytes(iii.value, dataByte); | ||||||
|  | 			} | ||||||
|  | 		} else if (type == Long.class) { | ||||||
| 			final Object tmp = field.get(data); | 			final Object tmp = field.get(data); | ||||||
| 			if (tmp == null) { | 			if (tmp == null) { | ||||||
| 				ps.setNull(iii.value, Types.BIGINT); | 				ps.setNull(iii.value, Types.BIGINT); | ||||||
| @@ -252,6 +262,14 @@ public class DataAccess { | |||||||
| 				final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant()); | 				final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant()); | ||||||
| 				ps.setTimestamp(iii.value, sqlDate); | 				ps.setTimestamp(iii.value, sqlDate); | ||||||
| 			} | 			} | ||||||
|  | 		} else if (type == Instant.class) { | ||||||
|  | 			final Object tmp = field.get(data); | ||||||
|  | 			if (tmp == null) { | ||||||
|  | 				ps.setNull(iii.value, Types.INTEGER); | ||||||
|  | 			} else { | ||||||
|  | 				final String sqlDate = ((Instant) tmp).toString(); | ||||||
|  | 				ps.setString(iii.value, sqlDate); | ||||||
|  | 			} | ||||||
| 		} else if (type == LocalDate.class) { | 		} else if (type == LocalDate.class) { | ||||||
| 			final Object tmp = field.get(data); | 			final Object tmp = field.get(data); | ||||||
| 			if (tmp == null) { | 			if (tmp == null) { | ||||||
| @@ -289,7 +307,18 @@ public class DataAccess { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	protected static <T> void setValueFromDb(final Class<?> type, final Object data, final CountInOut count, final Field field, final ResultSet rs, final CountInOut countNotNull) throws Exception { | 	protected static <T> void setValueFromDb(final Class<?> type, final Object data, final CountInOut count, final Field field, final ResultSet rs, final CountInOut countNotNull) throws Exception { | ||||||
| 		if (type == Long.class) { | 		if (type == UUID.class) { | ||||||
|  | 			final byte[] tmp = rs.getBytes(count.value); | ||||||
|  | 			// final UUID tmp = rs.getObject(count.value, UUID.class); | ||||||
|  | 			if (rs.wasNull()) { | ||||||
|  | 				field.set(data, null); | ||||||
|  | 			} else { | ||||||
|  | 				// field.set(data, tmp); | ||||||
|  | 				final UUID uuid = UuidUtils.asUuid(tmp); | ||||||
|  | 				field.set(data, uuid); | ||||||
|  | 				countNotNull.inc(); | ||||||
|  | 			} | ||||||
|  | 		} else if (type == Long.class) { | ||||||
| 			final Long tmp = rs.getLong(count.value); | 			final Long tmp = rs.getLong(count.value); | ||||||
| 			if (rs.wasNull()) { | 			if (rs.wasNull()) { | ||||||
| 				field.set(data, null); | 				field.set(data, null); | ||||||
| @@ -398,6 +427,14 @@ public class DataAccess { | |||||||
| 					countNotNull.inc(); | 					countNotNull.inc(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} else if (type == Instant.class) { | ||||||
|  | 			final String tmp = rs.getString(count.value); | ||||||
|  | 			if (rs.wasNull()) { | ||||||
|  | 				field.set(data, null); | ||||||
|  | 			} else { | ||||||
|  | 				field.set(data, Instant.parse(tmp)); | ||||||
|  | 				countNotNull.inc(); | ||||||
|  | 			} | ||||||
| 		} else if (type == LocalDate.class) { | 		} else if (type == LocalDate.class) { | ||||||
| 			final java.sql.Date tmp = rs.getDate(count.value); | 			final java.sql.Date tmp = rs.getDate(count.value); | ||||||
| 			if (rs.wasNull()) { | 			if (rs.wasNull()) { | ||||||
| @@ -447,6 +484,220 @@ public class DataAccess { | |||||||
| 		count.inc(); | 		count.inc(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// TODO: this function will replace the previous one !!! | ||||||
|  | 	protected static RetreiveFromDB createSetValueFromDbCallback(final int count, final Field field) throws Exception { | ||||||
|  | 		final Class<?> type = field.getType(); | ||||||
|  | 		if (type == UUID.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  |  | ||||||
|  | 				final byte[] tmp = rs.getBytes(count); | ||||||
|  | 				// final UUID tmp = rs.getObject(count, UUID.class); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					// field.set(obj, tmp); | ||||||
|  | 					final UUID uuid = UuidUtils.asUuid(tmp); | ||||||
|  | 					field.set(obj, uuid); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Long.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Long tmp = rs.getLong(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == long.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Long tmp = rs.getLong(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					// field.set(data, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.setLong(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Integer.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Integer tmp = rs.getInt(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == int.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Integer tmp = rs.getInt(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					// field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.setInt(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Float.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Float tmp = rs.getFloat(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == float.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Float tmp = rs.getFloat(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					// field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.setFloat(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Double.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Double tmp = rs.getDouble(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == double.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Double tmp = rs.getDouble(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					// field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.setDouble(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Boolean.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Boolean tmp = rs.getBoolean(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == boolean.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Boolean tmp = rs.getBoolean(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					// field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.setBoolean(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Timestamp.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Timestamp tmp = rs.getTimestamp(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Date.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				try { | ||||||
|  | 					final Timestamp tmp = rs.getTimestamp(count); | ||||||
|  | 					if (rs.wasNull()) { | ||||||
|  | 						field.set(obj, null); | ||||||
|  | 					} else { | ||||||
|  | 						field.set(obj, Date.from(tmp.toInstant())); | ||||||
|  | 					} | ||||||
|  | 				} catch (final SQLException ex) { | ||||||
|  | 					final String tmp = rs.getString(count); | ||||||
|  | 					LOGGER.error("Fail to parse the SQL time !!! {}", tmp); | ||||||
|  | 					if (rs.wasNull()) { | ||||||
|  | 						field.set(obj, null); | ||||||
|  | 					} else { | ||||||
|  | 						final Date date = DateTools.parseDate(tmp); | ||||||
|  | 						LOGGER.error("Fail to parse the SQL time !!! {}", date); | ||||||
|  | 						field.set(obj, date); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Instant.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final String tmp = rs.getString(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, Instant.parse(tmp)); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == LocalDate.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final java.sql.Date tmp = rs.getDate(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp.toLocalDate()); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == LocalTime.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final java.sql.Time tmp = rs.getTime(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp.toLocalTime()); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == String.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final String tmp = rs.getString(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					field.set(obj, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type.isEnum()) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final String tmp = rs.getString(count); | ||||||
|  | 				if (rs.wasNull()) { | ||||||
|  | 					field.set(obj, null); | ||||||
|  | 				} else { | ||||||
|  | 					boolean find = false; | ||||||
|  | 					final Object[] arr = type.getEnumConstants(); | ||||||
|  | 					for (final Object elem : arr) { | ||||||
|  | 						if (elem.toString().equals(tmp)) { | ||||||
|  | 							field.set(obj, elem); | ||||||
|  | 							find = true; | ||||||
|  | 							break; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					if (!find) { | ||||||
|  | 						throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'"); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		throw new DataAccessException("Unknown Field Type"); | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public static boolean isAddOnField(final Field field) { | 	public static boolean isAddOnField(final Field field) { | ||||||
| 		return findAddOnforField(field) != null; | 		return findAddOnforField(field) != null; | ||||||
| 	} | 	} | ||||||
| @@ -480,10 +731,13 @@ public class DataAccess { | |||||||
| 			check.getChecker().check("", data, AnnotationTools.getFieldsNames(clazz)); | 			check.getChecker().check("", data, AnnotationTools.getFieldsNames(clazz)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final List<Field> asyncFieldUpdate = new ArrayList<>(); | 		final List<Field> asyncFieldUpdate = new ArrayList<>(); | ||||||
| 		Long uniqueSQLID = null; | 		Long uniqueSQLID = null; | ||||||
|  | 		UUID uniqueSQLUUID = null; | ||||||
| 		final String tableName = AnnotationTools.getTableName(clazz, options); | 		final String tableName = AnnotationTools.getTableName(clazz, options); | ||||||
|  | 		Field primaryKeyField = null; | ||||||
|  | 		boolean generateUUID = false; | ||||||
| 		// real add in the BDD: | 		// real add in the BDD: | ||||||
| 		try { | 		try { | ||||||
| 			// boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; | 			// boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; | ||||||
| @@ -494,6 +748,30 @@ public class DataAccess { | |||||||
|  |  | ||||||
| 			boolean firstField = true; | 			boolean firstField = true; | ||||||
| 			int count = 0; | 			int count = 0; | ||||||
|  | 			for (final Field field : clazz.getFields()) { | ||||||
|  | 				// static field is only for internal global declaration ==> remove it .. | ||||||
|  | 				if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				if (AnnotationTools.isPrimaryKey(field)) { | ||||||
|  | 					primaryKeyField = field; | ||||||
|  | 					if (primaryKeyField.getType() != UUID.class) { | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 					generateUUID = true; | ||||||
|  | 					count++; | ||||||
|  | 					final String name = AnnotationTools.getFieldName(field); | ||||||
|  | 					if (firstField) { | ||||||
|  | 						firstField = false; | ||||||
|  | 					} else { | ||||||
|  | 						query.append(","); | ||||||
|  | 					} | ||||||
|  | 					query.append(" `"); | ||||||
|  | 					query.append(name); | ||||||
|  | 					query.append("`"); | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 			for (final Field field : clazz.getFields()) { | 			for (final Field field : clazz.getFields()) { | ||||||
| 				// static field is only for internal global declaration ==> remove it .. | 				// static field is only for internal global declaration ==> remove it .. | ||||||
| 				if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { | 				if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { | ||||||
| @@ -519,7 +797,7 @@ public class DataAccess { | |||||||
| 				} | 				} | ||||||
| 				if (!field.getClass().isPrimitive()) { | 				if (!field.getClass().isPrimitive()) { | ||||||
| 					final Object tmp = field.get(data); | 					final Object tmp = field.get(data); | ||||||
| 					if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) { | 					if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @@ -552,15 +830,22 @@ public class DataAccess { | |||||||
| 			LOGGER.warn("generate the query: '{}'", query.toString()); | 			LOGGER.warn("generate the query: '{}'", query.toString()); | ||||||
| 			// prepare the request: | 			// prepare the request: | ||||||
| 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | ||||||
| 			Field primaryKeyField = null; |  | ||||||
| 			final CountInOut iii = new CountInOut(1); | 			final CountInOut iii = new CountInOut(1); | ||||||
|  | 			UUID uuid = null; | ||||||
|  | 			if (generateUUID) { | ||||||
|  | 				firstField = false; | ||||||
|  | 				// uuid = UUID.randomUUID(); | ||||||
|  | 				uuid = UuidUtils.nextUUID(); | ||||||
|  | 				addElement(ps, uuid, iii); | ||||||
|  | 				iii.inc(); | ||||||
|  | 			} | ||||||
| 			for (final Field elem : clazz.getFields()) { | 			for (final Field elem : clazz.getFields()) { | ||||||
| 				// static field is only for internal global declaration ==> remove it .. | 				// static field is only for internal global declaration ==> remove it .. | ||||||
| 				if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { | 				if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 				if (AnnotationTools.isPrimaryKey(elem)) { | 				if (AnnotationTools.isPrimaryKey(elem)) { | ||||||
| 					primaryKeyField = elem; |  | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 				final DataAccessAddOn addOn = findAddOnforField(elem); | 				final DataAccessAddOn addOn = findAddOnforField(elem); | ||||||
| @@ -583,7 +868,7 @@ public class DataAccess { | |||||||
| 					final Class<?> type = elem.getType(); | 					final Class<?> type = elem.getType(); | ||||||
| 					if (!type.isPrimitive()) { | 					if (!type.isPrimitive()) { | ||||||
| 						final Object tmp = elem.get(data); | 						final Object tmp = elem.get(data); | ||||||
| 						if (tmp == null && elem.getDeclaredAnnotationsByType(DataDefault.class).length != 0) { | 						if (tmp == null && elem.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { | ||||||
| 							continue; | 							continue; | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| @@ -597,9 +882,23 @@ public class DataAccess { | |||||||
| 				throw new SQLException("Creating node failed, no rows affected."); | 				throw new SQLException("Creating node failed, no rows affected."); | ||||||
| 			} | 			} | ||||||
| 			// Retrieve uid inserted | 			// Retrieve uid inserted | ||||||
|  | 			if (generateUUID) { | ||||||
|  | 				// we generate the UUID, otherwise we can not retrieve it | ||||||
|  | 				uniqueSQLUUID = uuid; | ||||||
|  | 			} else { | ||||||
| 				try (ResultSet generatedKeys = ps.getGeneratedKeys()) { | 				try (ResultSet generatedKeys = ps.getGeneratedKeys()) { | ||||||
| 					if (generatedKeys.next()) { | 					if (generatedKeys.next()) { | ||||||
|  | 						if (primaryKeyField.getType() == UUID.class) { | ||||||
|  | 							// uniqueSQLUUID = generatedKeys.getObject(1, UUID.class); | ||||||
|  | 							/* final Object obj = generatedKeys.getObject(1); final BigInteger bigint = (BigInteger) generatedKeys.getObject(1); uniqueSQLUUID = UuidUtils.asUuid(bigint); final UUID | ||||||
|  | 							 * generatedUUID = (UUID) generatedKeys.getObject(1); System.out.println("UUID généré: " + generatedUUID); */ | ||||||
|  | 							final Object obj = generatedKeys.getObject(1); | ||||||
|  | 							final byte[] tmpid = generatedKeys.getBytes(1); | ||||||
|  | 							uniqueSQLUUID = UuidUtils.asUuid(tmpid); | ||||||
|  | 						} else { | ||||||
| 							uniqueSQLID = generatedKeys.getLong(1); | 							uniqueSQLID = generatedKeys.getLong(1); | ||||||
|  | 						} | ||||||
|  |  | ||||||
| 					} else { | 					} else { | ||||||
| 						throw new SQLException("Creating node failed, no ID obtained (1)."); | 						throw new SQLException("Creating node failed, no ID obtained (1)."); | ||||||
| 					} | 					} | ||||||
| @@ -608,21 +907,25 @@ public class DataAccess { | |||||||
| 					ex.printStackTrace(); | 					ex.printStackTrace(); | ||||||
| 					throw new SQLException("Creating node failed, no ID obtained (2)."); | 					throw new SQLException("Creating node failed, no ID obtained (2)."); | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
| 			if (primaryKeyField != null) { | 			if (primaryKeyField != null) { | ||||||
| 				if (primaryKeyField.getType() == Long.class) { | 				if (primaryKeyField.getType() == Long.class) { | ||||||
| 					primaryKeyField.set(data, uniqueSQLID); | 					primaryKeyField.set(data, uniqueSQLID); | ||||||
| 				} else if (primaryKeyField.getType() == long.class) { | 				} else if (primaryKeyField.getType() == long.class) { | ||||||
| 					primaryKeyField.setLong(data, uniqueSQLID); | 					primaryKeyField.setLong(data, uniqueSQLID); | ||||||
|  | 				} else if (primaryKeyField.getType() == UUID.class) { | ||||||
|  | 					primaryKeyField.set(data, uniqueSQLUUID); | ||||||
| 				} else { | 				} else { | ||||||
| 					LOGGER.error("Can not manage the primary filed !!!"); | 					LOGGER.error("Can not manage the primary filed !!!"); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			// ps.execute(); | 			// ps.execute(); | ||||||
| 		} catch (final SQLException ex) { | 		} catch (final SQLException ex) { | ||||||
|  | 			LOGGER.error("Fail SQL request: {}", ex.getMessage()); | ||||||
| 			ex.printStackTrace(); | 			ex.printStackTrace(); | ||||||
|  | 			throw new DataAccessException("Fail to Insert data in DB : " + ex.getMessage()); | ||||||
| 		} finally { | 		} finally { | ||||||
| 			entry.close(); | 			entry.close(); | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 		final List<LazyGetter> asyncActions = new ArrayList<>(); | 		final List<LazyGetter> asyncActions = new ArrayList<>(); | ||||||
| 		for (final Field field : asyncFieldUpdate) { | 		for (final Field field : asyncFieldUpdate) { | ||||||
| @@ -711,13 +1014,21 @@ public class DataAccess { | |||||||
| 	 * @param filterValue | 	 * @param filterValue | ||||||
| 	 * @return the affected rows. | 	 * @return the affected rows. | ||||||
| 	 * @throws Exception */ | 	 * @throws Exception */ | ||||||
| 	public static <T, ID_TYPE> int update(final T data, final ID_TYPE id, final List<String> updateColomn) throws Exception { | 	public static <T, ID_TYPE> int update(final T data, final ID_TYPE id, final List<String> updateColomn, final QueryOption... option) throws Exception { | ||||||
| 		return updateWhere(data, new Condition(getTableIdCondition(data.getClass(), id)), new FilterValue(updateColomn), new TransmitKey(id)); | 		final QueryOptions options = new QueryOptions(option); | ||||||
|  | 		options.add(new Condition(getTableIdCondition(data.getClass(), id))); | ||||||
|  | 		options.add(new FilterValue(updateColomn)); | ||||||
|  | 		options.add(new TransmitKey(id)); | ||||||
|  | 		return updateWhere(data, options); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static <T> int updateWhere(final T data, final QueryOption... option) throws Exception { | 	public static <T> int updateWhere(final T data, final QueryOption... option) throws Exception { | ||||||
| 		final Class<?> clazz = data.getClass(); |  | ||||||
| 		final QueryOptions options = new QueryOptions(option); | 		final QueryOptions options = new QueryOptions(option); | ||||||
|  | 		return updateWhere(data, options); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static <T> int updateWhere(final T data, final QueryOptions options) throws Exception { | ||||||
|  | 		final Class<?> clazz = data.getClass(); | ||||||
| 		final Condition condition = options.get(Condition.class); | 		final Condition condition = options.get(Condition.class); | ||||||
| 		if (condition == null) { | 		if (condition == null) { | ||||||
| 			throw new DataAccessException("request a gets without any condition"); | 			throw new DataAccessException("request a gets without any condition"); | ||||||
| @@ -734,9 +1045,9 @@ public class DataAccess { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		final List<LazyGetter> asyncActions = new ArrayList<>(); | 		final List<LazyGetter> asyncActions = new ArrayList<>(); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		// real add in the BDD: | 		// real add in the BDD: | ||||||
| 		try { | 		try (entry) { | ||||||
| 			final String tableName = AnnotationTools.getTableName(clazz, options); | 			final String tableName = AnnotationTools.getTableName(clazz, options); | ||||||
| 			// boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; | 			// boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; | ||||||
| 			final StringBuilder query = new StringBuilder(); | 			final StringBuilder query = new StringBuilder(); | ||||||
| @@ -769,7 +1080,7 @@ public class DataAccess { | |||||||
| 				} | 				} | ||||||
| 				if (!field.getClass().isPrimitive()) { | 				if (!field.getClass().isPrimitive()) { | ||||||
| 					final Object tmp = field.get(data); | 					final Object tmp = field.get(data); | ||||||
| 					if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) { | 					if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @@ -816,7 +1127,7 @@ public class DataAccess { | |||||||
| 						final Class<?> type = field.getType(); | 						final Class<?> type = field.getType(); | ||||||
| 						if (!type.isPrimitive()) { | 						if (!type.isPrimitive()) { | ||||||
| 							final Object tmp = field.get(data); | 							final Object tmp = field.get(data); | ||||||
| 							if (tmp == null && field.getDeclaredAnnotationsByType(DataDefault.class).length != 0) { | 							if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) { | ||||||
| 								continue; | 								continue; | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| @@ -830,9 +1141,6 @@ public class DataAccess { | |||||||
| 			} | 			} | ||||||
| 		} catch (final SQLException ex) { | 		} catch (final SQLException ex) { | ||||||
| 			ex.printStackTrace(); | 			ex.printStackTrace(); | ||||||
| 		} finally { |  | ||||||
| 			entry.close(); |  | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 		for (final LazyGetter action : asyncActions) { | 		for (final LazyGetter action : asyncActions) { | ||||||
| 			action.doRequest(); | 			action.doRequest(); | ||||||
| @@ -841,7 +1149,10 @@ public class DataAccess { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static void addElement(final PreparedStatement ps, final Object value, final CountInOut iii) throws Exception { | 	static void addElement(final PreparedStatement ps, final Object value, final CountInOut iii) throws Exception { | ||||||
| 		if (value instanceof final Long tmp) { | 		if (value instanceof final UUID tmp) { | ||||||
|  | 			final byte[] dataByte = UuidUtils.asBytes(tmp); | ||||||
|  | 			ps.setBytes(iii.value, dataByte); | ||||||
|  | 		} else if (value instanceof final Long tmp) { | ||||||
| 			LOGGER.debug("Inject Long => {}", tmp); | 			LOGGER.debug("Inject Long => {}", tmp); | ||||||
| 			ps.setLong(iii.value, tmp); | 			ps.setLong(iii.value, tmp); | ||||||
| 		} else if (value instanceof final Integer tmp) { | 		} else if (value instanceof final Integer tmp) { | ||||||
| @@ -885,26 +1196,20 @@ public class DataAccess { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static int executeSimpleQuerry(final String query, final boolean root) throws SQLException, IOException { | 	public static int executeSimpleQuerry(final String query, final QueryOption... option) throws SQLException, IOException { | ||||||
| 		final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); | 		final QueryOptions options = new QueryOptions(option); | ||||||
|  | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final Statement stmt = entry.connection.createStatement(); | 		final Statement stmt = entry.connection.createStatement(); | ||||||
| 		return stmt.executeUpdate(query); | 		return stmt.executeUpdate(query); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static int executeSimpleQuerry(final String query) throws SQLException, IOException { | 	public static boolean executeQuerry(final String query, final QueryOption... option) throws SQLException, IOException { | ||||||
| 		return executeSimpleQuerry(query, false); | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 	} | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
|  |  | ||||||
| 	public static boolean executeQuerry(final String query, final boolean root) throws SQLException, IOException { |  | ||||||
| 		final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); |  | ||||||
| 		final Statement stmt = entry.connection.createStatement(); | 		final Statement stmt = entry.connection.createStatement(); | ||||||
| 		return stmt.execute(query); | 		return stmt.execute(query); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static boolean executeQuerry(final String query) throws SQLException, IOException { |  | ||||||
| 		return executeQuerry(query, false); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception { | 	public static <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception { | ||||||
| 		final QueryOptions options = new QueryOptions(option); | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		options.add(new Limit(1)); | 		options.add(new Limit(1)); | ||||||
| @@ -915,8 +1220,6 @@ public class DataAccess { | |||||||
| 		return values.get(0); | 		return values.get(0); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* public static <T> List<T> getsWhere(final Class<T> clazz, final QueryItem condition) throws Exception { return getsWhere(clazz, condition, null); } */ |  | ||||||
|  |  | ||||||
| 	public static void generateSelectField(final StringBuilder querySelect, final StringBuilder query, final Class<?> clazz, final QueryOptions options, final CountInOut count) throws Exception { | 	public static void generateSelectField(final StringBuilder querySelect, final StringBuilder query, final Class<?> clazz, final QueryOptions options, final CountInOut count) throws Exception { | ||||||
| 		final boolean readAllfields = QueryOptions.readAllColomn(options); | 		final boolean readAllfields = QueryOptions.readAllColomn(options); | ||||||
| 		final String tableName = AnnotationTools.getTableName(clazz, options); | 		final String tableName = AnnotationTools.getTableName(clazz, options); | ||||||
| @@ -960,10 +1263,13 @@ public class DataAccess { | |||||||
|  |  | ||||||
| 	@SuppressWarnings("unchecked") | 	@SuppressWarnings("unchecked") | ||||||
| 	public static <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options) throws Exception { | 	public static <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options) throws Exception { | ||||||
| 		final Condition condition = options.get(Condition.class); | 		Condition condition = options.get(Condition.class); | ||||||
|  | 		if (condition == null) { | ||||||
|  | 			condition = new Condition(); | ||||||
|  | 		} | ||||||
| 		final List<LazyGetter> lazyCall = new ArrayList<>(); | 		final List<LazyGetter> lazyCall = new ArrayList<>(); | ||||||
| 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final List<T> outs = new ArrayList<>(); | 		final List<T> outs = new ArrayList<>(); | ||||||
| 		// real add in the BDD: | 		// real add in the BDD: | ||||||
| 		try { | 		try { | ||||||
| @@ -979,8 +1285,10 @@ public class DataAccess { | |||||||
| 			generateSelectField(querySelect, query, clazz, options, count); | 			generateSelectField(querySelect, query, clazz, options, count); | ||||||
| 			querySelect.append(query.toString()); | 			querySelect.append(query.toString()); | ||||||
| 			query = querySelect; | 			query = querySelect; | ||||||
| 			if (condition != null) { |  | ||||||
| 			condition.whereAppendQuery(query, tableName, options, deletedFieldName); | 			condition.whereAppendQuery(query, tableName, options, deletedFieldName); | ||||||
|  | 			final GroupBy groups = options.get(GroupBy.class); | ||||||
|  | 			if (groups != null) { | ||||||
|  | 				groups.generateQuerry(query, null); | ||||||
| 			} | 			} | ||||||
| 			final OrderBy orders = options.get(OrderBy.class); | 			final OrderBy orders = options.get(OrderBy.class); | ||||||
| 			if (orders != null) { | 			if (orders != null) { | ||||||
| @@ -994,9 +1302,7 @@ public class DataAccess { | |||||||
| 			// prepare the request: | 			// prepare the request: | ||||||
| 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | ||||||
| 			final CountInOut iii = new CountInOut(1); | 			final CountInOut iii = new CountInOut(1); | ||||||
| 			if (condition != null) { |  | ||||||
| 			condition.injectQuerry(ps, iii); | 			condition.injectQuerry(ps, iii); | ||||||
| 			} |  | ||||||
| 			if (limit != null) { | 			if (limit != null) { | ||||||
| 				limit.injectQuerry(ps, iii); | 				limit.injectQuerry(ps, iii); | ||||||
| 			} | 			} | ||||||
| @@ -1020,7 +1326,6 @@ public class DataAccess { | |||||||
| 			ex.printStackTrace(); | 			ex.printStackTrace(); | ||||||
| 		} finally { | 		} finally { | ||||||
| 			entry.close(); | 			entry.close(); | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 		return outs; | 		return outs; | ||||||
| 	} | 	} | ||||||
| @@ -1066,9 +1371,12 @@ public class DataAccess { | |||||||
|  |  | ||||||
| 	public static long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception { | 	public static long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception { | ||||||
| 		final QueryOptions options = new QueryOptions(option); | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		final Condition condition = options.get(Condition.class); | 		Condition condition = options.get(Condition.class); | ||||||
|  | 		if (condition == null) { | ||||||
|  | 			condition = new Condition(); | ||||||
|  | 		} | ||||||
| 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		long count = 0; | 		long count = 0; | ||||||
| 		// real add in the BDD: | 		// real add in the BDD: | ||||||
| 		try { | 		try { | ||||||
| @@ -1077,9 +1385,7 @@ public class DataAccess { | |||||||
| 			query.append("SELECT COUNT(*) AS count FROM `"); | 			query.append("SELECT COUNT(*) AS count FROM `"); | ||||||
| 			query.append(tableName); | 			query.append(tableName); | ||||||
| 			query.append("` "); | 			query.append("` "); | ||||||
| 			if (condition != null) { |  | ||||||
| 			condition.whereAppendQuery(query, tableName, options, deletedFieldName); | 			condition.whereAppendQuery(query, tableName, options, deletedFieldName); | ||||||
| 			} |  | ||||||
| 			final Limit limit = options.get(Limit.class); | 			final Limit limit = options.get(Limit.class); | ||||||
| 			if (limit != null) { | 			if (limit != null) { | ||||||
| 				limit.generateQuerry(query, tableName); | 				limit.generateQuerry(query, tableName); | ||||||
| @@ -1088,9 +1394,7 @@ public class DataAccess { | |||||||
| 			// prepare the request: | 			// prepare the request: | ||||||
| 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | ||||||
| 			final CountInOut iii = new CountInOut(1); | 			final CountInOut iii = new CountInOut(1); | ||||||
| 			if (condition != null) { |  | ||||||
| 			condition.injectQuerry(ps, iii); | 			condition.injectQuerry(ps, iii); | ||||||
| 			} |  | ||||||
| 			if (limit != null) { | 			if (limit != null) { | ||||||
| 				limit.injectQuerry(ps, iii); | 				limit.injectQuerry(ps, iii); | ||||||
| 			} | 			} | ||||||
| @@ -1174,8 +1478,7 @@ public class DataAccess { | |||||||
| 		final String tableName = AnnotationTools.getTableName(clazz, options); | 		final String tableName = AnnotationTools.getTableName(clazz, options); | ||||||
| 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | ||||||
| 		// find the deleted field | 		// find the deleted field | ||||||
|  | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); |  | ||||||
| 		final StringBuilder query = new StringBuilder(); | 		final StringBuilder query = new StringBuilder(); | ||||||
| 		query.append("DELETE FROM `"); | 		query.append("DELETE FROM `"); | ||||||
| 		query.append(tableName); | 		query.append(tableName); | ||||||
| @@ -1189,7 +1492,6 @@ public class DataAccess { | |||||||
| 			return ps.executeUpdate(); | 			return ps.executeUpdate(); | ||||||
| 		} finally { | 		} finally { | ||||||
| 			entry.close(); | 			entry.close(); | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1209,8 +1511,7 @@ public class DataAccess { | |||||||
| 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | 		final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | ||||||
| 		/* String updateFieldName = null; if ("sqlite".equalsIgnoreCase(ConfigBaseVariable.getDBType())) { updateFieldName = AnnotationTools.getUpdatedFieldName(clazz); } */ | 		/* String updateFieldName = null; if ("sqlite".equalsIgnoreCase(ConfigBaseVariable.getDBType())) { updateFieldName = AnnotationTools.getUpdatedFieldName(clazz); } */ | ||||||
| 		// find the deleted field | 		// find the deleted field | ||||||
|  | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); |  | ||||||
| 		final StringBuilder query = new StringBuilder(); | 		final StringBuilder query = new StringBuilder(); | ||||||
| 		query.append("UPDATE `"); | 		query.append("UPDATE `"); | ||||||
| 		query.append(tableName); | 		query.append(tableName); | ||||||
| @@ -1228,7 +1529,6 @@ public class DataAccess { | |||||||
| 			return ps.executeUpdate(); | 			return ps.executeUpdate(); | ||||||
| 		} finally { | 		} finally { | ||||||
| 			entry.close(); | 			entry.close(); | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1253,7 +1553,7 @@ public class DataAccess { | |||||||
| 		if (deletedFieldName == null) { | 		if (deletedFieldName == null) { | ||||||
| 			throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field"); | 			throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field"); | ||||||
| 		} | 		} | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final StringBuilder query = new StringBuilder(); | 		final StringBuilder query = new StringBuilder(); | ||||||
| 		query.append("UPDATE `"); | 		query.append("UPDATE `"); | ||||||
| 		query.append(tableName); | 		query.append(tableName); | ||||||
| @@ -1270,14 +1570,13 @@ public class DataAccess { | |||||||
| 			return ps.executeUpdate(); | 			return ps.executeUpdate(); | ||||||
| 		} finally { | 		} finally { | ||||||
| 			entry.close(); | 			entry.close(); | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static void drop(final Class<?> clazz, final QueryOption... option) throws Exception { | 	public static void drop(final Class<?> clazz, final QueryOption... option) throws Exception { | ||||||
| 		final QueryOptions options = new QueryOptions(option); | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		final String tableName = AnnotationTools.getTableName(clazz, options); | 		final String tableName = AnnotationTools.getTableName(clazz, options); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final StringBuilder query = new StringBuilder(); | 		final StringBuilder query = new StringBuilder(); | ||||||
| 		query.append("DROP TABLE IF EXISTS `"); | 		query.append("DROP TABLE IF EXISTS `"); | ||||||
| 		query.append(tableName); | 		query.append(tableName); | ||||||
| @@ -1303,14 +1602,13 @@ public class DataAccess { | |||||||
| 			} | 			} | ||||||
| 		} finally { | 		} finally { | ||||||
| 			entry.close(); | 			entry.close(); | ||||||
| 			entry = null; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception { | 	public static void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception { | ||||||
| 		final QueryOptions options = new QueryOptions(option); | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		final String tableName = AnnotationTools.getTableName(clazz, options); | 		final String tableName = AnnotationTools.getTableName(clazz, options); | ||||||
| 		DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | 		DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
| 		final StringBuilder query = new StringBuilder(); | 		final StringBuilder query = new StringBuilder(); | ||||||
| 		query.append("DELETE FROM `"); | 		query.append("DELETE FROM `"); | ||||||
| 		query.append(tableName); | 		query.append(tableName); | ||||||
| @@ -1340,4 +1638,110 @@ public class DataAccess { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** Execute a simple query with external property. | ||||||
|  | 	 * @param <TYPE> Type of the data generate. | ||||||
|  | 	 * @param clazz Class that might be analyze. | ||||||
|  | 	 * @param query Base of the query. | ||||||
|  | 	 * @param parameters "?" parameter of the query. | ||||||
|  | 	 * @param option Optional parameters | ||||||
|  | 	 * @return The list of element requested | ||||||
|  | 	 * @throws Exception */ | ||||||
|  | 	public static <TYPE> List<TYPE> query(final Class<TYPE> clazz, final String query, final List<Object> parameters, final QueryOption... option) throws Exception { | ||||||
|  | 		final QueryOptions options = new QueryOptions(option); | ||||||
|  | 		return query(clazz, query, parameters, options); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static <TYPE> List<TYPE> query(final Class<TYPE> clazz, final String queryBase, final List<Object> parameters, final QueryOptions options) throws Exception { | ||||||
|  | 		final List<LazyGetter> lazyCall = new ArrayList<>(); | ||||||
|  | 		// TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | ||||||
|  | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
|  |  | ||||||
|  | 		Condition condition = options.get(Condition.class); | ||||||
|  | 		if (condition == null) { | ||||||
|  | 			condition = new Condition(); | ||||||
|  | 		} | ||||||
|  | 		final StringBuilder query = new StringBuilder(queryBase); | ||||||
|  | 		final List<TYPE> outs = new ArrayList<>(); | ||||||
|  | 		// real add in the BDD: | ||||||
|  | 		try { | ||||||
|  | 			final CountInOut count = new CountInOut(); | ||||||
|  | 			condition.whereAppendQuery(query, null, options, null); | ||||||
|  |  | ||||||
|  | 			final GroupBy groups = options.get(GroupBy.class); | ||||||
|  | 			if (groups != null) { | ||||||
|  | 				groups.generateQuerry(query, null); | ||||||
|  | 			} | ||||||
|  | 			final OrderBy orders = options.get(OrderBy.class); | ||||||
|  | 			if (orders != null) { | ||||||
|  | 				orders.generateQuerry(query, null); | ||||||
|  | 			} | ||||||
|  | 			final Limit limit = options.get(Limit.class); | ||||||
|  | 			if (limit != null) { | ||||||
|  | 				limit.generateQuerry(query, null); | ||||||
|  | 			} | ||||||
|  | 			LOGGER.warn("generate the query: '{}'", query.toString()); | ||||||
|  | 			// prepare the request: | ||||||
|  | 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | ||||||
|  | 			final CountInOut iii = new CountInOut(1); | ||||||
|  | 			if (parameters != null) { | ||||||
|  | 				for (final Object elem : parameters) { | ||||||
|  | 					DataAccess.addElement(ps, elem, iii); | ||||||
|  | 				} | ||||||
|  | 				iii.inc(); | ||||||
|  | 			} | ||||||
|  | 			condition.injectQuerry(ps, iii); | ||||||
|  | 			if (limit != null) { | ||||||
|  | 				limit.injectQuerry(ps, iii); | ||||||
|  | 			} | ||||||
|  | 			// execute the request | ||||||
|  | 			final ResultSet rs = ps.executeQuery(); | ||||||
|  | 			final ResultSetMetaData rsmd = rs.getMetaData(); | ||||||
|  | 			final List<RetreiveFromDB> actionToRetreive = new ArrayList<>(); | ||||||
|  | 			LOGGER.info("Field:"); | ||||||
|  | 			for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) { | ||||||
|  | 				final String label = rsmd.getColumnLabel(jjj + 1); | ||||||
|  | 				LOGGER.info("    - {}:{}", jjj, label); | ||||||
|  | 				// find field name ... | ||||||
|  | 				final Field field = AnnotationTools.getFieldNamed(clazz, label); | ||||||
|  | 				if (field == null) { | ||||||
|  | 					throw new DataAccessException("Querry with unknown field: '" + label + "'"); | ||||||
|  | 				} | ||||||
|  | 				// create the callback... | ||||||
|  | 				final RetreiveFromDB element = createSetValueFromDbCallback(jjj + 1, field); | ||||||
|  | 				actionToRetreive.add(element); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			while (rs.next()) { | ||||||
|  | 				count.value = 1; | ||||||
|  | 				Object data = null; | ||||||
|  | 				for (final Constructor<?> contructor : clazz.getConstructors()) { | ||||||
|  | 					if (contructor.getParameterCount() == 0) { | ||||||
|  | 						data = contructor.newInstance(); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if (data == null) { | ||||||
|  | 					// TODO... | ||||||
|  | 				} else { | ||||||
|  | 					for (final RetreiveFromDB action : actionToRetreive) { | ||||||
|  | 						action.doRequest(rs, data); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				@SuppressWarnings("unchecked") | ||||||
|  | 				final TYPE out = (TYPE) data; | ||||||
|  | 				outs.add(out); | ||||||
|  | 			} | ||||||
|  | 			LOGGER.info("Async calls: {}", lazyCall.size()); | ||||||
|  | 			for (final LazyGetter elem : lazyCall) { | ||||||
|  | 				elem.doRequest(); | ||||||
|  | 			} | ||||||
|  | 		} catch (final SQLException ex) { | ||||||
|  | 			ex.printStackTrace(); | ||||||
|  | 			throw ex; | ||||||
|  | 		} catch (final Exception ex) { | ||||||
|  | 			ex.printStackTrace(); | ||||||
|  | 		} finally { | ||||||
|  | 			entry.close(); | ||||||
|  | 		} | ||||||
|  | 		return outs; | ||||||
|  | 	} | ||||||
| } | } | ||||||
							
								
								
									
										399
									
								
								src/org/kar/archidata/dataAccess/DataExport.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								src/org/kar/archidata/dataAccess/DataExport.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,399 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.sql.PreparedStatement; | ||||||
|  | import java.sql.ResultSet; | ||||||
|  | import java.sql.ResultSetMetaData; | ||||||
|  | import java.sql.SQLException; | ||||||
|  | import java.sql.Statement; | ||||||
|  | import java.sql.Timestamp; | ||||||
|  | import java.time.Instant; | ||||||
|  | import java.time.LocalDate; | ||||||
|  | import java.time.LocalTime; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.dataAccess.exportTools.TableQuery; | ||||||
|  | import org.kar.archidata.dataAccess.exportTools.TableQueryTypes; | ||||||
|  | import org.kar.archidata.dataAccess.options.Condition; | ||||||
|  | import org.kar.archidata.dataAccess.options.DBInterfaceOption; | ||||||
|  | import org.kar.archidata.db.DBEntry; | ||||||
|  | import org.kar.archidata.exception.DataAccessException; | ||||||
|  | import org.kar.archidata.tools.DateTools; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  |  | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  |  | ||||||
|  | public class DataExport { | ||||||
|  | 	static final Logger LOGGER = LoggerFactory.getLogger(DataExport.class); | ||||||
|  | 	public static final String CSV_TYPE = "text/csv"; | ||||||
|  |  | ||||||
|  | 	@SuppressWarnings("unchecked") | ||||||
|  | 	protected static RetreiveFromDB createSetValueFromDbCallbackTable(final int count, final Class<?> type, final int id) throws Exception { | ||||||
|  | 		if (type == UUID.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final UUID tmp = rs.getObject(count, UUID.class); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Long.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Long tmp = rs.getLong(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == long.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Long tmp = rs.getLong(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Integer.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Integer tmp = rs.getInt(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == int.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Integer tmp = rs.getInt(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Float.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Float tmp = rs.getFloat(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == float.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Float tmp = rs.getFloat(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Double.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Double tmp = rs.getDouble(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == double.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Double tmp = rs.getDouble(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Boolean.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Boolean tmp = rs.getBoolean(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == boolean.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Boolean tmp = rs.getBoolean(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Timestamp.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final Timestamp tmp = rs.getTimestamp(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Date.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				try { | ||||||
|  | 					final Timestamp tmp = rs.getTimestamp(count); | ||||||
|  | 					if (!rs.wasNull()) { | ||||||
|  | 						final List<Object> data = (List<Object>) (obj); | ||||||
|  | 						data.set(id, Date.from(tmp.toInstant())); | ||||||
|  | 					} | ||||||
|  | 				} catch (final SQLException ex) { | ||||||
|  | 					final String tmp = rs.getString(count); | ||||||
|  | 					LOGGER.error("Fail to parse the SQL time !!! {}", tmp); | ||||||
|  | 					if (!rs.wasNull()) { | ||||||
|  | 						final Date date = DateTools.parseDate(tmp); | ||||||
|  | 						LOGGER.error("Fail to parse the SQL time !!! {}", date); | ||||||
|  | 						final List<Object> data = (List<Object>) (obj); | ||||||
|  | 						data.set(id, date); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == Instant.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final String tmp = rs.getString(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final Instant date = Instant.parse(tmp); | ||||||
|  | 					LOGGER.error("Fail to parse the SQL time !!! {}", date); | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, date); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == LocalDate.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final java.sql.Date tmp = rs.getDate(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp.toLocalDate()); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == LocalTime.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final java.sql.Time tmp = rs.getTime(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp.toLocalTime()); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type == String.class) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final String tmp = rs.getString(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					final List<Object> data = (List<Object>) (obj); | ||||||
|  | 					data.set(id, tmp); | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		if (type.isEnum()) { | ||||||
|  | 			return (final ResultSet rs, final Object obj) -> { | ||||||
|  | 				final String tmp = rs.getString(count); | ||||||
|  | 				if (!rs.wasNull()) { | ||||||
|  | 					boolean find = false; | ||||||
|  | 					final Object[] arr = type.getEnumConstants(); | ||||||
|  | 					for (final Object elem : arr) { | ||||||
|  | 						if (elem.toString().equals(tmp)) { | ||||||
|  | 							final List<Object> data = (List<Object>) (obj); | ||||||
|  | 							data.set(id, elem); | ||||||
|  | 							find = true; | ||||||
|  | 							break; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					if (!find) { | ||||||
|  | 						throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'"); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 		throw new DataAccessException("Unknown Field Type"); | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private static int getQueryPropertyId(final List<TableQueryTypes> properties, final String name) throws DataAccessException { | ||||||
|  | 		for (int iii = 0; iii < properties.size(); iii++) { | ||||||
|  | 			if (properties.get(iii).name.equals(name)) { | ||||||
|  | 				return iii; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		throw new DataAccessException("Querry with unknown field: '" + name + "'"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static TableQuery queryTable(final List<TableQueryTypes> headers, final String query, final List<Object> parameters, final QueryOption... option) throws Exception { | ||||||
|  | 		final QueryOptions options = new QueryOptions(option); | ||||||
|  | 		return queryTable(headers, query, parameters, options); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static TableQuery queryTable(final List<TableQueryTypes> headers, final String queryBase, final List<Object> parameters, final QueryOptions options) throws Exception { | ||||||
|  | 		final List<LazyGetter> lazyCall = new ArrayList<>(); | ||||||
|  | 		// TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); | ||||||
|  | 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | ||||||
|  |  | ||||||
|  | 		Condition condition = options.get(Condition.class); | ||||||
|  | 		if (condition == null) { | ||||||
|  | 			condition = new Condition(); | ||||||
|  | 		} | ||||||
|  | 		final StringBuilder query = new StringBuilder(queryBase); | ||||||
|  | 		final TableQuery out = new TableQuery(headers); | ||||||
|  | 		// real add in the BDD: | ||||||
|  | 		try { | ||||||
|  | 			final CountInOut count = new CountInOut(); | ||||||
|  | 			condition.whereAppendQuery(query, null, options, null); | ||||||
|  |  | ||||||
|  | 			final GroupBy groups = options.get(GroupBy.class); | ||||||
|  | 			if (groups != null) { | ||||||
|  | 				groups.generateQuerry(query, null); | ||||||
|  | 			} | ||||||
|  | 			final OrderBy orders = options.get(OrderBy.class); | ||||||
|  | 			if (orders != null) { | ||||||
|  | 				orders.generateQuerry(query, null); | ||||||
|  | 			} | ||||||
|  | 			final Limit limit = options.get(Limit.class); | ||||||
|  | 			if (limit != null) { | ||||||
|  | 				limit.generateQuerry(query, null); | ||||||
|  | 			} | ||||||
|  | 			LOGGER.warn("generate the query: '{}'", query.toString()); | ||||||
|  | 			// prepare the request: | ||||||
|  | 			final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); | ||||||
|  | 			final CountInOut iii = new CountInOut(1); | ||||||
|  | 			if (parameters != null) { | ||||||
|  | 				for (final Object elem : parameters) { | ||||||
|  | 					DataAccess.addElement(ps, elem, iii); | ||||||
|  | 				} | ||||||
|  | 				iii.inc(); | ||||||
|  | 			} | ||||||
|  | 			condition.injectQuerry(ps, iii); | ||||||
|  | 			if (limit != null) { | ||||||
|  | 				limit.injectQuerry(ps, iii); | ||||||
|  | 			} | ||||||
|  | 			// execute the request | ||||||
|  | 			final ResultSet rs = ps.executeQuery(); | ||||||
|  | 			final ResultSetMetaData rsmd = rs.getMetaData(); | ||||||
|  | 			final List<RetreiveFromDB> actionToRetreive = new ArrayList<>(); | ||||||
|  | 			LOGGER.info("Field:"); | ||||||
|  | 			for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) { | ||||||
|  | 				final String label = rsmd.getColumnLabel(jjj + 1); | ||||||
|  | 				final String typeName = rsmd.getColumnTypeName(jjj + 1); | ||||||
|  | 				final int typeId = rsmd.getColumnType(jjj + 1); | ||||||
|  | 				final int id = getQueryPropertyId(headers, label); | ||||||
|  | 				LOGGER.info("    - {}:{} type=[{}] {}  REQUEST={}", jjj, label, typeId, typeName, headers.get(id).type.getCanonicalName()); | ||||||
|  | 				// create the callback... | ||||||
|  | 				final RetreiveFromDB element = createSetValueFromDbCallbackTable(jjj + 1, headers.get(id).type, id); | ||||||
|  | 				actionToRetreive.add(element); | ||||||
|  | 			} | ||||||
|  | 			while (rs.next()) { | ||||||
|  | 				count.value = 1; | ||||||
|  | 				final List<Object> data = Arrays.asList(new Object[headers.size()]); | ||||||
|  | 				for (final RetreiveFromDB action : actionToRetreive) { | ||||||
|  | 					action.doRequest(rs, data); | ||||||
|  | 				} | ||||||
|  | 				out.values.add(data); | ||||||
|  | 			} | ||||||
|  | 			LOGGER.info("Async calls: {}", lazyCall.size()); | ||||||
|  | 			for (final LazyGetter elem : lazyCall) { | ||||||
|  | 				elem.doRequest(); | ||||||
|  | 			} | ||||||
|  | 		} catch (final SQLException ex) { | ||||||
|  | 			ex.printStackTrace(); | ||||||
|  | 			throw ex; | ||||||
|  | 		} catch (final Exception ex) { | ||||||
|  | 			ex.printStackTrace(); | ||||||
|  | 		} finally { | ||||||
|  | 			entry.close(); | ||||||
|  | 		} | ||||||
|  | 		return out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String CSVReplaceSeparator(final String data, final String separator) { | ||||||
|  | 		if (data == null) { | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
|  | 		final String separatorLine = "\n"; | ||||||
|  | 		final String separatorLineReplace = "\\n"; | ||||||
|  | 		return data.replaceAll(separator, "__SEP__").replaceAll(separatorLine, separatorLineReplace); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String tableToCSV(final TableQuery data) { | ||||||
|  | 		final String separator = ";"; | ||||||
|  | 		final StringBuilder out = new StringBuilder(); | ||||||
|  | 		// generate header: | ||||||
|  | 		boolean first = true; | ||||||
|  | 		for (final TableQueryTypes elem : data.headers) { | ||||||
|  | 			if (!first) { | ||||||
|  | 				out.append(separator); | ||||||
|  | 			} else { | ||||||
|  | 				first = false; | ||||||
|  | 			} | ||||||
|  | 			out.append(CSVReplaceSeparator(elem.title, separator)); | ||||||
|  | 		} | ||||||
|  | 		out.append("\n"); | ||||||
|  | 		// generate body: | ||||||
|  | 		first = true; | ||||||
|  | 		for (final List<Object> line : data.values) { | ||||||
|  | 			for (final Object elem : line) { | ||||||
|  | 				if (!first) { | ||||||
|  | 					out.append(separator); | ||||||
|  | 				} else { | ||||||
|  | 					first = false; | ||||||
|  | 				} | ||||||
|  | 				if (elem != null) { | ||||||
|  | 					out.append(CSVReplaceSeparator(elem.toString(), separator)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			out.append("\n"); | ||||||
|  | 		} | ||||||
|  | 		return out.toString(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static Response convertInResponse(final TableQuery dataOut, final String accept) throws DataAccessException, IOException { | ||||||
|  | 		if (CSV_TYPE.equals(accept)) { | ||||||
|  | 			// CSV serialization | ||||||
|  | 			String out = null; | ||||||
|  | 			try { | ||||||
|  | 				out = DataExport.tableToCSV(dataOut); | ||||||
|  | 			} catch (final Exception e) { | ||||||
|  | 				LOGGER.error("Fail to generate CSV...."); | ||||||
|  | 				e.printStackTrace(); | ||||||
|  | 				throw new DataAccessException("Fail in CSV convertion data"); | ||||||
|  | 			} | ||||||
|  | 			return Response.ok(out).header("Content-Type", CSV_TYPE).build(); | ||||||
|  | 		} | ||||||
|  | 		if (MediaType.APPLICATION_JSON.equals(accept)) { | ||||||
|  | 			LOGGER.info("Start mapping josn"); | ||||||
|  | 			final ObjectMapper objectMapper = new ObjectMapper(); | ||||||
|  | 			LOGGER.info("Start find modules josn"); | ||||||
|  | 			objectMapper.findAndRegisterModules(); | ||||||
|  | 			LOGGER.info("Start map object"); | ||||||
|  | 			String out; | ||||||
|  | 			try { | ||||||
|  | 				out = objectMapper.writeValueAsString(dataOut); | ||||||
|  | 			} catch (final JsonProcessingException e) { | ||||||
|  | 				LOGGER.error("Fail to generate JSON...."); | ||||||
|  | 				e.printStackTrace(); | ||||||
|  | 				throw new DataAccessException("Fail in JSON convertion data"); | ||||||
|  | 			} | ||||||
|  | 			LOGGER.info("generate response"); | ||||||
|  | 			return Response.ok(out).header("Content-Type", MediaType.APPLICATION_JSON).build(); | ||||||
|  | 		} | ||||||
|  | 		throw new IOException("This type is not managed: '" + accept + "'"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -2,11 +2,13 @@ package org.kar.archidata.dataAccess; | |||||||
|  |  | ||||||
| import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||||
| import java.sql.Timestamp; | import java.sql.Timestamp; | ||||||
|  | import java.time.Instant; | ||||||
| import java.time.LocalDate; | import java.time.LocalDate; | ||||||
| import java.time.LocalTime; | import java.time.LocalTime; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.AnnotationTools; | import org.kar.archidata.annotation.AnnotationTools; | ||||||
| import org.kar.archidata.annotation.CreationTimestamp; | import org.kar.archidata.annotation.CreationTimestamp; | ||||||
| @@ -27,6 +29,9 @@ public class DataFactory { | |||||||
|  |  | ||||||
| 	public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws Exception { | 	public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws Exception { | ||||||
| 		if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | 		if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | ||||||
|  | 			if (type == UUID.class) { | ||||||
|  | 				return "binary(16)"; | ||||||
|  | 			} | ||||||
| 			if (type == Long.class || type == long.class) { | 			if (type == Long.class || type == long.class) { | ||||||
| 				return "bigint"; | 				return "bigint"; | ||||||
| 			} | 			} | ||||||
| @@ -42,6 +47,9 @@ public class DataFactory { | |||||||
| 			if (type == Double.class || type == double.class) { | 			if (type == Double.class || type == double.class) { | ||||||
| 				return "double"; | 				return "double"; | ||||||
| 			} | 			} | ||||||
|  | 			if (type == Instant.class) { | ||||||
|  | 				return "varchar(33)"; | ||||||
|  | 			} | ||||||
| 			if (type == Date.class || type == Timestamp.class) { | 			if (type == Date.class || type == Timestamp.class) { | ||||||
| 				return "timestamp(3)"; | 				return "timestamp(3)"; | ||||||
| 			} | 			} | ||||||
| @@ -75,6 +83,9 @@ public class DataFactory { | |||||||
| 				return out.toString(); | 				return out.toString(); | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
|  | 			if (type == UUID.class) { | ||||||
|  | 				return "BINARY(16)"; | ||||||
|  | 			} | ||||||
| 			if (type == Long.class || type == long.class) { | 			if (type == Long.class || type == long.class) { | ||||||
| 				return "INTEGER"; | 				return "INTEGER"; | ||||||
| 			} | 			} | ||||||
| @@ -90,6 +101,9 @@ public class DataFactory { | |||||||
| 			if (type == Double.class || type == double.class) { | 			if (type == Double.class || type == double.class) { | ||||||
| 				return "REAL"; | 				return "REAL"; | ||||||
| 			} | 			} | ||||||
|  | 			if (type == Instant.class) { | ||||||
|  | 				return "text"; | ||||||
|  | 			} | ||||||
| 			if (type == Date.class || type == Timestamp.class) { | 			if (type == Date.class || type == Timestamp.class) { | ||||||
| 				return "DATETIME"; | 				return "DATETIME"; | ||||||
| 			} | 			} | ||||||
| @@ -172,16 +186,24 @@ public class DataFactory { | |||||||
| 			} | 			} | ||||||
| 			if (defaultValue == null) { | 			if (defaultValue == null) { | ||||||
| 				if (updateTime || createTime) { | 				if (updateTime || createTime) { | ||||||
|  | 					if ("varchar(33)".equals(typeValue)) { | ||||||
|  | 						mainTableBuilder.append("DEFAULT DATE_FORMAT(now(6), '%Y-%m-%dT%H:%m:%s.%fZ')"); | ||||||
|  | 					} else { | ||||||
| 						mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP"); | 						mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP"); | ||||||
| 						if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | 						if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | ||||||
| 							mainTableBuilder.append("(3)"); | 							mainTableBuilder.append("(3)"); | ||||||
| 						} | 						} | ||||||
|  | 					} | ||||||
| 					mainTableBuilder.append(" "); | 					mainTableBuilder.append(" "); | ||||||
| 				} | 				} | ||||||
| 				if (updateTime) { | 				if (updateTime) { | ||||||
| 					if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | 					if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | ||||||
|  | 						if ("varchar(33)".equals(typeValue)) { | ||||||
|  | 							mainTableBuilder.append("ON UPDATE DATE_FORMAT(now(6), '%Y-%m-%dT%H:%m:%s.%fZ')"); | ||||||
|  | 						} else { | ||||||
| 							mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP"); | 							mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP"); | ||||||
| 							mainTableBuilder.append("(3)"); | 							mainTableBuilder.append("(3)"); | ||||||
|  | 						} | ||||||
| 					} else { | 					} else { | ||||||
| 						// TODO: add trigger: | 						// TODO: add trigger: | ||||||
| 						/* CREATE TRIGGER your_table_trig AFTER UPDATE ON your_table BEGIN update your_table SET updated_on = datetime('now') WHERE user_id = NEW.user_id; END; */ | 						/* CREATE TRIGGER your_table_trig AFTER UPDATE ON your_table BEGIN update your_table SET updated_on = datetime('now') WHERE user_id = NEW.user_id; END; */ | ||||||
| @@ -195,7 +217,11 @@ public class DataFactory { | |||||||
| 						triggerBuilder.append(" SET "); | 						triggerBuilder.append(" SET "); | ||||||
| 						triggerBuilder.append(name); | 						triggerBuilder.append(name); | ||||||
| 						// triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n"); | 						// triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n"); | ||||||
|  | 						if ("varchar(33)".equals(typeValue)) { | ||||||
|  | 							triggerBuilder.append(" = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = NEW.id; \n"); | ||||||
|  | 						} else { | ||||||
| 							triggerBuilder.append(" = strftime('%Y-%m-%d %H:%M:%f', 'now') WHERE id = NEW.id; \n"); | 							triggerBuilder.append(" = strftime('%Y-%m-%d %H:%M:%f', 'now') WHERE id = NEW.id; \n"); | ||||||
|  | 						} | ||||||
| 						triggerBuilder.append("END;"); | 						triggerBuilder.append("END;"); | ||||||
|  |  | ||||||
| 						postOtherTables.add(triggerBuilder.toString()); | 						postOtherTables.add(triggerBuilder.toString()); | ||||||
| @@ -241,8 +267,11 @@ public class DataFactory { | |||||||
| 			mainTableBuilder.append("PRIMARY KEY "); | 			mainTableBuilder.append("PRIMARY KEY "); | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (strategy == GenerationType.IDENTITY) { | 		if (strategy == GenerationType.IDENTITY) { | ||||||
| 			if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | 			if ("binary(16)".equals(typeValue)) { | ||||||
|  |  | ||||||
|  | 			} else if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { | ||||||
| 				mainTableBuilder.append("AUTO_INCREMENT "); | 				mainTableBuilder.append("AUTO_INCREMENT "); | ||||||
| 			} else { | 			} else { | ||||||
| 				mainTableBuilder.append("AUTOINCREMENT "); | 				mainTableBuilder.append("AUTOINCREMENT "); | ||||||
|   | |||||||
							
								
								
									
										590
									
								
								src/org/kar/archidata/dataAccess/DataFactoryTsApi.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										590
									
								
								src/org/kar/archidata/dataAccess/DataFactoryTsApi.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,590 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.io.BufferedReader; | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.FileWriter; | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.io.InputStreamReader; | ||||||
|  | import java.lang.annotation.Annotation; | ||||||
|  | import java.lang.reflect.Method; | ||||||
|  | import java.lang.reflect.Parameter; | ||||||
|  | import java.lang.reflect.ParameterizedType; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.HashSet; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Map.Entry; | ||||||
|  | import java.util.Set; | ||||||
|  |  | ||||||
|  | import org.glassfish.jersey.media.multipart.FormDataParam; | ||||||
|  | import org.kar.archidata.annotation.AsyncType; | ||||||
|  | import org.kar.archidata.annotation.TypeScriptProgress; | ||||||
|  | import org.kar.archidata.catcher.RestErrorResponse; | ||||||
|  | import org.kar.archidata.dataAccess.DataFactoryZod.ClassElement; | ||||||
|  | import org.kar.archidata.dataAccess.DataFactoryZod.GeneratedTypes; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.Operation; | ||||||
|  | import jakarta.ws.rs.Consumes; | ||||||
|  | import jakarta.ws.rs.DELETE; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.PATCH; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.PUT; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.PathParam; | ||||||
|  | import jakarta.ws.rs.Produces; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | import jakarta.ws.rs.core.Context; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  |  | ||||||
|  | public class DataFactoryTsApi { | ||||||
|  | 	static final Logger LOGGER = LoggerFactory.getLogger(DataFactoryTsApi.class); | ||||||
|  |  | ||||||
|  | 	record APIModel(String data, String className) { | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** Request the generation of the TypeScript file for the "Zod" export model | ||||||
|  | 	 * @param classs List of class used in the model | ||||||
|  | 	 * @throws Exception */ | ||||||
|  | 	public static List<String> createApi(final List<Class<?>> classs, final GeneratedTypes previous, final String pathPackage) throws Exception { | ||||||
|  | 		final List<String> apis = new ArrayList<>(); | ||||||
|  | 		final String globalheader = """ | ||||||
|  | 				/** | ||||||
|  | 				 * API of the server (auto-generated code) | ||||||
|  | 				 */ | ||||||
|  | 				import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools" | ||||||
|  | 				import { """; | ||||||
|  |  | ||||||
|  | 		for (final Class<?> clazz : classs) { | ||||||
|  | 			final Set<Class<?>> includeModel = new HashSet<>(); | ||||||
|  | 			final Set<Class<?>> includeCheckerModel = new HashSet<>(); | ||||||
|  | 			final APIModel api = createSingleApi(clazz, includeModel, includeCheckerModel, previous); | ||||||
|  | 			final StringBuilder generatedData = new StringBuilder(); | ||||||
|  | 			generatedData.append(globalheader); | ||||||
|  | 			for (final Class<?> elem : includeModel) { | ||||||
|  | 				if (elem == null) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				final ClassElement classElement = DataFactoryZod.createTable(elem, previous); | ||||||
|  | 				if (classElement.nativeType) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				generatedData.append(classElement.tsTypeName); | ||||||
|  | 				generatedData.append(", "); | ||||||
|  | 			} | ||||||
|  | 			for (final Class<?> elem : includeCheckerModel) { | ||||||
|  | 				if (elem == null) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				final ClassElement classElement = DataFactoryZod.createTable(elem, previous); | ||||||
|  | 				if (classElement.nativeType) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				generatedData.append(classElement.tsCheckType); | ||||||
|  | 				generatedData.append(", "); | ||||||
|  | 			} | ||||||
|  | 			generatedData.append("} from \"./model\"\n"); | ||||||
|  | 			generatedData.append(api.data()); | ||||||
|  |  | ||||||
|  | 			String fileName = api.className(); | ||||||
|  | 			fileName = fileName.replaceAll("([A-Z])", "-$1").toLowerCase(); | ||||||
|  | 			fileName = fileName.replaceAll("^\\-*", ""); | ||||||
|  | 			apis.add(fileName); | ||||||
|  | 			final FileWriter myWriter = new FileWriter(pathPackage + File.separator + fileName + ".ts"); | ||||||
|  | 			myWriter.write(generatedData.toString()); | ||||||
|  | 			myWriter.close(); | ||||||
|  | 		} | ||||||
|  | 		return apis; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetPath(final Class<?> element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Path.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((Path) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static List<String> apiAnnotationProduces(final Class<?> element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Produces.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return Arrays.asList(((Produces) annotation[0]).value()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static List<String> apiAnnotationProduces(final Method element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Produces.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return Arrays.asList(((Produces) annotation[0]).value()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static boolean apiAnnotationTypeScriptProgress(final Method element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(TypeScriptProgress.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static List<String> apiAnnotationProduces(final Class<?> clazz, final Method method) throws Exception { | ||||||
|  | 		final List<String> data = apiAnnotationProduces(method); | ||||||
|  | 		if (data != null) { | ||||||
|  | 			return data; | ||||||
|  | 		} | ||||||
|  | 		return apiAnnotationProduces(clazz); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetOperationDescription(final Method element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Operation.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((Operation) annotation[0]).description(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetPath(final Method element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Path.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((Path) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetTypeRequest(final Method element) throws Exception { | ||||||
|  | 		if (element.getDeclaredAnnotationsByType(GET.class).length == 1) { | ||||||
|  | 			return "GET"; | ||||||
|  | 		} | ||||||
|  | 		if (element.getDeclaredAnnotationsByType(POST.class).length == 1) { | ||||||
|  | 			return "POST"; | ||||||
|  | 		} | ||||||
|  | 		if (element.getDeclaredAnnotationsByType(PUT.class).length == 1) { | ||||||
|  | 			return "PUT"; | ||||||
|  | 		} | ||||||
|  | 		if (element.getDeclaredAnnotationsByType(PATCH.class).length == 1) { | ||||||
|  | 			return "PATCH"; | ||||||
|  | 		} | ||||||
|  | 		if (element.getDeclaredAnnotationsByType(DELETE.class).length == 1) { | ||||||
|  | 			return "DELETE"; | ||||||
|  | 		} | ||||||
|  | 		return null; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetPathParam(final Parameter element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(PathParam.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((PathParam) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetQueryParam(final Parameter element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(QueryParam.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((QueryParam) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String apiAnnotationGetFormDataParam(final Parameter element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(FormDataParam.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((FormDataParam) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static Class<?> apiAnnotationGetAsyncType(final Parameter element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(AsyncType.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((AsyncType) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static Class<?> apiAnnotationGetAsyncType(final Method element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(AsyncType.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return ((AsyncType) annotation[0]).value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static List<String> apiAnnotationGetConsumes(final Method element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Consumes.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return Arrays.asList(((Consumes) annotation[0]).value()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static List<String> apiAnnotationGetConsumes(final Class<?> element) throws Exception { | ||||||
|  | 		final Annotation[] annotation = element.getDeclaredAnnotationsByType(Consumes.class); | ||||||
|  | 		if (annotation.length == 0) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return Arrays.asList(((Consumes) annotation[0]).value()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static List<String> apiAnnotationGetConsumes(final Class<?> clazz, final Method method) throws Exception { | ||||||
|  | 		final List<String> data = apiAnnotationGetConsumes(method); | ||||||
|  | 		if (data != null) { | ||||||
|  | 			return data; | ||||||
|  | 		} | ||||||
|  | 		return apiAnnotationGetConsumes(clazz); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static boolean apiAnnotationIsContext(final Parameter element) throws Exception { | ||||||
|  | 		return element.getDeclaredAnnotationsByType(Context.class).length != 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static APIModel createSingleApi(final Class<?> clazz, final Set<Class<?>> includeModel, final Set<Class<?>> includeCheckerModel, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		final StringBuilder builder = new StringBuilder(); | ||||||
|  | 		// the basic path has no specific elements... | ||||||
|  | 		final String basicPath = apiAnnotationGetPath(clazz); | ||||||
|  | 		final String classSimpleName = clazz.getSimpleName(); | ||||||
|  |  | ||||||
|  | 		builder.append("export namespace "); | ||||||
|  | 		builder.append(classSimpleName); | ||||||
|  | 		builder.append(" {\n"); | ||||||
|  | 		LOGGER.info("Parse Class for path: {} => {}", classSimpleName, basicPath); | ||||||
|  | 		for (final Method method : clazz.getDeclaredMethods()) { | ||||||
|  | 			final String methodName = method.getName(); | ||||||
|  | 			final String methodPath = apiAnnotationGetPath(method); | ||||||
|  | 			final String methodType = apiAnnotationGetTypeRequest(method); | ||||||
|  | 			if (methodType == null) { | ||||||
|  | 				LOGGER.error("    [{}] {} => {}/{} ==> No methode type @PATH, @GET ...", methodType, methodName, basicPath, methodPath); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			final String methodDescription = apiAnnotationGetOperationDescription(method); | ||||||
|  | 			final List<String> consumes = apiAnnotationGetConsumes(clazz, method); | ||||||
|  | 			final List<String> produces = apiAnnotationProduces(clazz, method); | ||||||
|  | 			LOGGER.trace("    [{}] {} => {}/{}", methodType, methodName, basicPath, methodPath); | ||||||
|  | 			if (methodDescription != null) { | ||||||
|  | 				LOGGER.trace("         description: {}", methodDescription); | ||||||
|  | 			} | ||||||
|  | 			final boolean needGenerateProgress = apiAnnotationTypeScriptProgress(method); | ||||||
|  | 			Class<?> returnTypeModel = apiAnnotationGetAsyncType(method); | ||||||
|  | 			if (returnTypeModel == null) { | ||||||
|  | 				returnTypeModel = method.getReturnType(); | ||||||
|  | 			} | ||||||
|  | 			boolean isUnmanagedReturnType = false; | ||||||
|  | 			if (returnTypeModel == Response.class) { | ||||||
|  | 				isUnmanagedReturnType = true; | ||||||
|  | 				returnTypeModel = Void.class; | ||||||
|  | 			} | ||||||
|  | 			boolean returnModelIsArray = false; | ||||||
|  | 			ClassElement tmpReturn; | ||||||
|  | 			if (returnTypeModel == List.class) { | ||||||
|  | 				final ParameterizedType listType = (ParameterizedType) method.getGenericReturnType(); | ||||||
|  | 				returnTypeModel = (Class<?>) listType.getActualTypeArguments()[0]; | ||||||
|  | 				tmpReturn = DataFactoryZod.createTable(returnTypeModel, previous); | ||||||
|  | 				returnModelIsArray = true; | ||||||
|  | 				includeModel.add(tmpReturn.model[0]); | ||||||
|  | 			} else { | ||||||
|  | 				tmpReturn = DataFactoryZod.createTable(returnTypeModel, previous); | ||||||
|  |  | ||||||
|  | 			} | ||||||
|  | 			includeModel.add(tmpReturn.model[0]); | ||||||
|  | 			includeCheckerModel.add(tmpReturn.model[0]); | ||||||
|  | 			LOGGER.trace("         return: {}", tmpReturn.tsTypeName); | ||||||
|  | 			final Map<String, String> queryParams = new HashMap<>(); | ||||||
|  | 			final Map<String, String> pathParams = new HashMap<>(); | ||||||
|  | 			final Map<String, String> formDataParams = new HashMap<>(); | ||||||
|  | 			final List<String> emptyElement = new ArrayList<>(); | ||||||
|  | 			// LOGGER.info(" Parameters:"); | ||||||
|  | 			for (final Parameter parameter : method.getParameters()) { | ||||||
|  | 				// Security context are internal parameter (not available from API) | ||||||
|  | 				if (apiAnnotationIsContext(parameter)) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				final Class<?> parameterType = parameter.getType(); | ||||||
|  | 				String parameterTypeString; | ||||||
|  | 				final Class<?> asyncType = apiAnnotationGetAsyncType(parameter); | ||||||
|  | 				if (parameterType == List.class) { | ||||||
|  | 					if (asyncType == null) { | ||||||
|  | 						LOGGER.warn("Detext List param ==> not managed type ==> any[] !!!"); | ||||||
|  | 						parameterTypeString = "any[]"; | ||||||
|  | 					} else { | ||||||
|  | 						final ClassElement tmp = DataFactoryZod.createTable(asyncType, previous); | ||||||
|  | 						includeModel.add(tmp.model[0]); | ||||||
|  | 						parameterTypeString = tmp.tsTypeName + "[]"; | ||||||
|  | 					} | ||||||
|  | 				} else if (asyncType == null) { | ||||||
|  | 					final ClassElement tmp = DataFactoryZod.createTable(parameterType, previous); | ||||||
|  | 					includeModel.add(tmp.model[0]); | ||||||
|  | 					parameterTypeString = tmp.tsTypeName; | ||||||
|  | 				} else { | ||||||
|  | 					final ClassElement tmp = DataFactoryZod.createTable(asyncType, previous); | ||||||
|  | 					includeModel.add(tmp.model[0]); | ||||||
|  | 					parameterTypeString = tmp.tsTypeName; | ||||||
|  | 				} | ||||||
|  | 				final String pathParam = apiAnnotationGetPathParam(parameter); | ||||||
|  | 				final String queryParam = apiAnnotationGetQueryParam(parameter); | ||||||
|  | 				final String formDataParam = apiAnnotationGetFormDataParam(parameter); | ||||||
|  | 				if (queryParam != null) { | ||||||
|  | 					queryParams.put(queryParam, parameterTypeString); | ||||||
|  | 				} else if (pathParam != null) { | ||||||
|  | 					pathParams.put(pathParam, parameterTypeString); | ||||||
|  | 				} else if (formDataParam != null) { | ||||||
|  | 					formDataParams.put(formDataParam, parameterTypeString); | ||||||
|  | 				} else if (asyncType != null) { | ||||||
|  | 					final ClassElement tmp = DataFactoryZod.createTable(asyncType, previous); | ||||||
|  | 					includeModel.add(tmp.model[0]); | ||||||
|  | 					emptyElement.add(tmp.tsTypeName); | ||||||
|  | 				} else if (parameterType == List.class) { | ||||||
|  | 					parameterTypeString = "any[]"; | ||||||
|  | 					final Class<?> plop = parameterType.arrayType(); | ||||||
|  | 					LOGGER.info("ArrayType = {}", plop); | ||||||
|  | 				} else { | ||||||
|  | 					final ClassElement tmp = DataFactoryZod.createTable(parameterType, previous); | ||||||
|  | 					includeModel.add(tmp.model[0]); | ||||||
|  | 					emptyElement.add(tmp.tsTypeName); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (!queryParams.isEmpty()) { | ||||||
|  | 				LOGGER.trace("         Query parameter:"); | ||||||
|  | 				for (final Entry<String, String> queryEntry : queryParams.entrySet()) { | ||||||
|  | 					LOGGER.trace("             - {}: {}", queryEntry.getKey(), queryEntry.getValue()); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (!pathParams.isEmpty()) { | ||||||
|  | 				LOGGER.trace("         Path parameter:"); | ||||||
|  | 				for (final Entry<String, String> pathEntry : pathParams.entrySet()) { | ||||||
|  | 					LOGGER.trace("             - {}: {}", pathEntry.getKey(), pathEntry.getValue()); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (emptyElement.size() > 1) { | ||||||
|  | 				LOGGER.error("         Fail to parse: Too much element in the model for the data ..."); | ||||||
|  | 				continue; | ||||||
|  | 			} else if (emptyElement.size() == 1 && formDataParams.size() != 0) { | ||||||
|  | 				LOGGER.error("         Fail to parse: Incompatible form data & direct data ..."); | ||||||
|  | 				continue; | ||||||
|  | 			} else if (emptyElement.size() == 1) { | ||||||
|  | 				LOGGER.trace("         data type: {}", emptyElement.get(0)); | ||||||
|  | 			} | ||||||
|  | 			// ALL is good can generate the Elements | ||||||
|  |  | ||||||
|  | 			if (methodDescription != null) { | ||||||
|  | 				builder.append("\n\t/**\n\t * "); | ||||||
|  | 				builder.append(methodDescription); | ||||||
|  | 				builder.append("\n\t */"); | ||||||
|  | 			} | ||||||
|  | 			if (isUnmanagedReturnType) { | ||||||
|  | 				builder.append("\n\t// TODO: unmanaged \"Response\" type: please specify @AsyncType or considered as 'void'."); | ||||||
|  | 			} | ||||||
|  | 			builder.append("\n\texport function "); | ||||||
|  | 			builder.append(methodName); | ||||||
|  | 			builder.append("({ restConfig,"); | ||||||
|  | 			if (!queryParams.isEmpty()) { | ||||||
|  | 				builder.append(" queries,"); | ||||||
|  | 			} | ||||||
|  | 			if (!pathParams.isEmpty()) { | ||||||
|  | 				builder.append(" params,"); | ||||||
|  | 			} | ||||||
|  | 			if (produces.size() > 1) { | ||||||
|  | 				builder.append(" produce,"); | ||||||
|  | 			} | ||||||
|  | 			if (emptyElement.size() == 1) { | ||||||
|  | 				builder.append(" data,"); | ||||||
|  | 			} else if (formDataParams.size() != 0) { | ||||||
|  | 				builder.append(" data,"); | ||||||
|  | 			} | ||||||
|  | 			if (needGenerateProgress) { | ||||||
|  | 				builder.append(" callback,"); | ||||||
|  | 			} | ||||||
|  | 			builder.append(" }: {"); | ||||||
|  | 			builder.append("\n\t\trestConfig: RESTConfig,"); | ||||||
|  | 			if (!queryParams.isEmpty()) { | ||||||
|  | 				builder.append("\n\t\tqueries: {"); | ||||||
|  | 				for (final Entry<String, String> queryEntry : queryParams.entrySet()) { | ||||||
|  | 					builder.append("\n\t\t\t"); | ||||||
|  | 					builder.append(queryEntry.getKey()); | ||||||
|  | 					builder.append(": "); | ||||||
|  | 					builder.append(queryEntry.getValue()); | ||||||
|  | 					builder.append(","); | ||||||
|  | 				} | ||||||
|  | 				builder.append("\n\t\t},"); | ||||||
|  | 			} | ||||||
|  | 			if (!pathParams.isEmpty()) { | ||||||
|  | 				builder.append("\n\t\tparams: {"); | ||||||
|  | 				for (final Entry<String, String> pathEntry : pathParams.entrySet()) { | ||||||
|  | 					builder.append("\n\t\t\t"); | ||||||
|  | 					builder.append(pathEntry.getKey()); | ||||||
|  | 					builder.append(": "); | ||||||
|  | 					builder.append(pathEntry.getValue()); | ||||||
|  | 					builder.append(","); | ||||||
|  | 				} | ||||||
|  | 				builder.append("\n\t\t},"); | ||||||
|  | 			} | ||||||
|  | 			if (emptyElement.size() == 1) { | ||||||
|  | 				builder.append("\n\t\tdata: "); | ||||||
|  | 				builder.append(emptyElement.get(0)); | ||||||
|  | 				builder.append(","); | ||||||
|  | 			} else if (formDataParams.size() != 0) { | ||||||
|  | 				builder.append("\n\t\tdata: {"); | ||||||
|  | 				for (final Entry<String, String> pathEntry : formDataParams.entrySet()) { | ||||||
|  | 					builder.append("\n\t\t\t"); | ||||||
|  | 					builder.append(pathEntry.getKey()); | ||||||
|  | 					builder.append(": "); | ||||||
|  | 					builder.append(pathEntry.getValue()); | ||||||
|  | 					builder.append(","); | ||||||
|  | 				} | ||||||
|  | 				builder.append("\n\t\t},"); | ||||||
|  | 			} | ||||||
|  | 			if (produces.size() > 1) { | ||||||
|  | 				builder.append("\n\t\tproduce: "); | ||||||
|  | 				String isFist = null; | ||||||
|  | 				for (final String elem : produces) { | ||||||
|  | 					String lastElement = null; | ||||||
|  |  | ||||||
|  | 					if (MediaType.APPLICATION_JSON.equals(elem)) { | ||||||
|  | 						lastElement = "HTTPMimeType.JSON"; | ||||||
|  | 					} | ||||||
|  | 					if (MediaType.MULTIPART_FORM_DATA.equals(elem)) { | ||||||
|  | 						lastElement = "HTTPMimeType.MULTIPART"; | ||||||
|  | 					} | ||||||
|  | 					if (DataExport.CSV_TYPE.equals(elem)) { | ||||||
|  | 						lastElement = "HTTPMimeType.CSV"; | ||||||
|  | 					} | ||||||
|  | 					if (lastElement != null) { | ||||||
|  | 						if (isFist == null) { | ||||||
|  | 							isFist = lastElement; | ||||||
|  | 						} else { | ||||||
|  | 							builder.append(" | "); | ||||||
|  | 						} | ||||||
|  | 						builder.append(lastElement); | ||||||
|  | 					} else { | ||||||
|  | 						LOGGER.error("Unmanaged model type: {}", elem); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				builder.append(","); | ||||||
|  | 			} | ||||||
|  | 			if (needGenerateProgress) { | ||||||
|  | 				builder.append("\n\t\tcallback?: RESTCallbacks,"); | ||||||
|  | 			} | ||||||
|  | 			builder.append("\n\t}): Promise<"); | ||||||
|  | 			builder.append(tmpReturn.tsTypeName); | ||||||
|  | 			if (returnModelIsArray) { | ||||||
|  | 				builder.append("[]"); | ||||||
|  | 			} | ||||||
|  | 			builder.append("> {"); | ||||||
|  | 			if (tmpReturn.tsTypeName.equals("void")) { | ||||||
|  | 				builder.append("\n\t\treturn RESTRequestVoid({"); | ||||||
|  | 			} else if (returnModelIsArray) { | ||||||
|  | 				builder.append("\n\t\treturn RESTRequestJsonArray({"); | ||||||
|  | 			} else { | ||||||
|  | 				builder.append("\n\t\treturn RESTRequestJson({"); | ||||||
|  | 			} | ||||||
|  | 			builder.append("\n\t\t\trestModel: {"); | ||||||
|  | 			builder.append("\n\t\t\t\tendPoint: \""); | ||||||
|  | 			builder.append(basicPath); | ||||||
|  | 			if (methodPath != null) { | ||||||
|  | 				builder.append("/"); | ||||||
|  | 				builder.append(methodPath); | ||||||
|  | 			} | ||||||
|  | 			builder.append("\","); | ||||||
|  | 			builder.append("\n\t\t\t\trequestType: HTTPRequestModel."); | ||||||
|  | 			builder.append(methodType); | ||||||
|  | 			builder.append(","); | ||||||
|  | 			if (consumes != null) { | ||||||
|  | 				for (final String elem : consumes) { | ||||||
|  | 					if (MediaType.APPLICATION_JSON.equals(elem)) { | ||||||
|  | 						builder.append("\n\t\t\t\tcontentType: HTTPMimeType.JSON,"); | ||||||
|  | 						break; | ||||||
|  | 					} else if (MediaType.MULTIPART_FORM_DATA.equals(elem)) { | ||||||
|  | 						builder.append("\n\t\t\t\tcontentType: HTTPMimeType.MULTIPART,"); | ||||||
|  | 						break; | ||||||
|  | 					} else if (MediaType.TEXT_PLAIN.equals(elem)) { | ||||||
|  | 						builder.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,"); | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} else if ("DELETE".equals(methodType)) { | ||||||
|  | 				builder.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,"); | ||||||
|  | 			} | ||||||
|  | 			if (produces != null) { | ||||||
|  | 				if (produces.size() > 1) { | ||||||
|  | 					builder.append("\n\t\t\t\taccept: produce,"); | ||||||
|  | 				} else { | ||||||
|  | 					for (final String elem : produces) { | ||||||
|  | 						if (MediaType.APPLICATION_JSON.equals(elem)) { | ||||||
|  | 							builder.append("\n\t\t\t\taccept: HTTPMimeType.JSON,"); | ||||||
|  | 							break; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			builder.append("\n\t\t\t},"); | ||||||
|  | 			builder.append("\n\t\t\trestConfig,"); | ||||||
|  | 			if (!pathParams.isEmpty()) { | ||||||
|  | 				builder.append("\n\t\t\tparams,"); | ||||||
|  | 			} | ||||||
|  | 			if (!queryParams.isEmpty()) { | ||||||
|  | 				builder.append("\n\t\t\tqueries,"); | ||||||
|  | 			} | ||||||
|  | 			if (emptyElement.size() == 1) { | ||||||
|  | 				builder.append("\n\t\t\tdata,"); | ||||||
|  | 			} else if (formDataParams.size() != 0) { | ||||||
|  | 				builder.append("\n\t\t\tdata,"); | ||||||
|  | 			} | ||||||
|  | 			if (needGenerateProgress) { | ||||||
|  | 				builder.append("\n\t\t\tcallback,"); | ||||||
|  | 			} | ||||||
|  | 			builder.append("\n\t\t}"); | ||||||
|  | 			if (tmpReturn.tsCheckType != null) { | ||||||
|  | 				builder.append(", "); | ||||||
|  | 				builder.append(tmpReturn.tsCheckType); | ||||||
|  | 			} | ||||||
|  | 			builder.append(");"); | ||||||
|  | 			builder.append("\n\t};"); | ||||||
|  | 		} | ||||||
|  | 		builder.append("\n}\n"); | ||||||
|  | 		return new APIModel(builder.toString(), classSimpleName); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void generatePackage(final List<Class<?>> classApi, final List<Class<?>> classModel, final String pathPackage) throws Exception { | ||||||
|  | 		final GeneratedTypes previous = DataFactoryZod.createBasicType(); | ||||||
|  | 		DataFactoryZod.createTable(RestErrorResponse.class, previous); | ||||||
|  | 		final List<String> listApi = createApi(classApi, previous, pathPackage); | ||||||
|  | 		final String packageApi = DataFactoryZod.createTables(new ArrayList<>(classModel), previous); | ||||||
|  | 		FileWriter myWriter = new FileWriter(pathPackage + File.separator + "model.ts"); | ||||||
|  | 		myWriter.write(packageApi.toString()); | ||||||
|  | 		myWriter.close(); | ||||||
|  |  | ||||||
|  | 		final StringBuilder index = new StringBuilder(""" | ||||||
|  | 				/** | ||||||
|  | 				 * Global import of the package | ||||||
|  | 				 */ | ||||||
|  | 				export * from "./model"; | ||||||
|  | 				"""); | ||||||
|  | 		for (final String api : listApi) { | ||||||
|  | 			index.append("export * from \"./").append(api).append("\";\n"); | ||||||
|  | 		} | ||||||
|  | 		myWriter = new FileWriter(pathPackage + File.separator + "index.ts"); | ||||||
|  | 		myWriter.write(index.toString()); | ||||||
|  | 		myWriter.close(); | ||||||
|  | 		final InputStream ioStream = DataFactoryTsApi.class.getClassLoader().getResourceAsStream("rest-tools.ts"); | ||||||
|  | 		if (ioStream == null) { | ||||||
|  | 			throw new IllegalArgumentException("rest-tools.ts is not found"); | ||||||
|  | 		} | ||||||
|  | 		final BufferedReader buffer = new BufferedReader(new InputStreamReader(ioStream)); | ||||||
|  | 		myWriter = new FileWriter(pathPackage + File.separator + "rest-tools.ts"); | ||||||
|  | 		String line; | ||||||
|  | 		while ((line = buffer.readLine()) != null) { | ||||||
|  | 			myWriter.write(line); | ||||||
|  | 			myWriter.write("\n"); | ||||||
|  | 		} | ||||||
|  | 		ioStream.close(); | ||||||
|  | 		myWriter.close(); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										444
									
								
								src/org/kar/archidata/dataAccess/DataFactoryZod.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								src/org/kar/archidata/dataAccess/DataFactoryZod.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,444 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.FileWriter; | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.lang.reflect.Field; | ||||||
|  | import java.lang.reflect.ParameterizedType; | ||||||
|  | import java.sql.Timestamp; | ||||||
|  | import java.time.Instant; | ||||||
|  | import java.time.LocalDate; | ||||||
|  | import java.time.LocalTime; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.glassfish.jersey.media.multipart.FormDataContentDisposition; | ||||||
|  | import org.kar.archidata.annotation.AnnotationTools; | ||||||
|  | import org.kar.archidata.exception.DataAccessException; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | public class DataFactoryZod { | ||||||
|  | 	static final Logger LOGGER = LoggerFactory.getLogger(DataFactoryZod.class); | ||||||
|  |  | ||||||
|  | 	static public class ClassElement { | ||||||
|  | 		public Class<?>[] model; | ||||||
|  | 		public String zodName; | ||||||
|  | 		public String tsTypeName; | ||||||
|  | 		public String tsCheckType; | ||||||
|  | 		public String declaration; | ||||||
|  | 		public String comment = null; | ||||||
|  | 		public boolean isEnum = false; | ||||||
|  | 		public boolean nativeType; | ||||||
|  |  | ||||||
|  | 		public ClassElement(final Class<?> model[], final String zodName, final String tsTypeName, final String tsCheckType, final String declaration, final boolean nativeType) { | ||||||
|  | 			this.model = model; | ||||||
|  | 			this.zodName = zodName; | ||||||
|  | 			this.tsTypeName = tsTypeName; | ||||||
|  | 			this.tsCheckType = tsCheckType; | ||||||
|  | 			this.declaration = declaration; | ||||||
|  | 			this.nativeType = nativeType; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public ClassElement(final Class<?> model) { | ||||||
|  | 			this(new Class<?>[] { model }); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public ClassElement(final Class<?> model[]) { | ||||||
|  | 			this.model = model; | ||||||
|  | 			this.zodName = "Zod" + model[0].getSimpleName(); | ||||||
|  | 			this.tsTypeName = model[0].getSimpleName(); | ||||||
|  | 			this.tsCheckType = "is" + model[0].getSimpleName(); | ||||||
|  | 			this.declaration = null; | ||||||
|  | 			this.nativeType = false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static class GeneratedTypes { | ||||||
|  | 		final List<ClassElement> previousGeneration = new ArrayList<>(); | ||||||
|  | 		final List<Class<?>> order = new ArrayList<>(); | ||||||
|  |  | ||||||
|  | 		public ClassElement find(final Class<?> clazz) { | ||||||
|  | 			for (final ClassElement elem : this.previousGeneration) { | ||||||
|  | 				for (final Class<?> elemClass : elem.model) { | ||||||
|  | 					if (elemClass == clazz) { | ||||||
|  | 						return elem; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public void add(final ClassElement elem) { | ||||||
|  | 			this.previousGeneration.add(elem); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public void add(final ClassElement elem, final boolean addOrder) { | ||||||
|  | 			this.previousGeneration.add(elem); | ||||||
|  | 			if (addOrder) { | ||||||
|  | 				this.order.add(elem.model[0]); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public void addOrder(final ClassElement elem) { | ||||||
|  | 			this.order.add(elem.model[0]); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static ClassElement convertTypeZodEnum(final Class<?> clazz, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		final ClassElement element = new ClassElement(clazz); | ||||||
|  | 		previous.add(element); | ||||||
|  | 		final Object[] arr = clazz.getEnumConstants(); | ||||||
|  | 		final StringBuilder out = new StringBuilder(); | ||||||
|  | 		if (System.getenv("ARCHIDATA_GENERATE_ZOD_ENUM") != null) { | ||||||
|  | 			boolean first = true; | ||||||
|  | 			out.append("zod.enum(["); | ||||||
|  | 			for (final Object elem : arr) { | ||||||
|  | 				if (!first) { | ||||||
|  | 					out.append(",\n\t"); | ||||||
|  | 				} else { | ||||||
|  | 					out.append("\n\t"); | ||||||
|  | 					first = false; | ||||||
|  | 				} | ||||||
|  | 				out.append("'"); | ||||||
|  | 				out.append(elem.toString()); | ||||||
|  | 				out.append("'"); | ||||||
|  | 			} | ||||||
|  | 			if (first) { | ||||||
|  | 				out.append("]}"); | ||||||
|  | 			} else { | ||||||
|  | 				out.append("\n\t])"); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			element.isEnum = true; | ||||||
|  | 			boolean first = true; | ||||||
|  | 			out.append("{"); | ||||||
|  | 			for (final Object elem : arr) { | ||||||
|  | 				if (!first) { | ||||||
|  | 					out.append(",\n\t"); | ||||||
|  | 				} else { | ||||||
|  | 					out.append("\n\t"); | ||||||
|  | 					first = false; | ||||||
|  | 				} | ||||||
|  | 				out.append(elem.toString()); | ||||||
|  | 				out.append(" = '"); | ||||||
|  | 				out.append(elem.toString()); | ||||||
|  | 				out.append("'"); | ||||||
|  | 			} | ||||||
|  | 			if (first) { | ||||||
|  | 				out.append("}"); | ||||||
|  | 			} else { | ||||||
|  | 				out.append(",\n\t}"); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		element.declaration = out.toString(); | ||||||
|  | 		previous.addOrder(element); | ||||||
|  | 		return element; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String convertTypeZod(final Class<?> type, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		final ClassElement previousType = previous.find(type); | ||||||
|  | 		if (previousType != null) { | ||||||
|  | 			return previousType.zodName; | ||||||
|  | 		} | ||||||
|  | 		if (type.isEnum()) { | ||||||
|  | 			return convertTypeZodEnum(type, previous).zodName; | ||||||
|  | 		} | ||||||
|  | 		if (type == List.class) { | ||||||
|  | 			throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName() + " Unmanaged List of List ... "); | ||||||
|  | 		} | ||||||
|  | 		final ClassElement elemCreated = createTable(type, previous); | ||||||
|  | 		if (elemCreated != null) { | ||||||
|  | 			return elemCreated.zodName; | ||||||
|  | 		} | ||||||
|  | 		throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String convertTypeZod(final Field field, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		final Class<?> type = field.getType(); | ||||||
|  | 		final ClassElement previousType = previous.find(type); | ||||||
|  | 		if (previousType != null) { | ||||||
|  | 			return previousType.zodName; | ||||||
|  | 		} | ||||||
|  | 		if (type.isEnum()) { | ||||||
|  | 			return convertTypeZodEnum(type, previous).zodName; | ||||||
|  | 		} | ||||||
|  | 		if (type == List.class) { | ||||||
|  | 			final ParameterizedType listType = (ParameterizedType) field.getGenericType(); | ||||||
|  | 			final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0]; | ||||||
|  | 			final String simpleSubType = convertTypeZod(listClass, previous); | ||||||
|  | 			return "zod.array(" + simpleSubType + ")"; | ||||||
|  | 		} | ||||||
|  | 		final ClassElement elemCreated = createTable(type, previous); | ||||||
|  | 		if (elemCreated != null) { | ||||||
|  | 			return elemCreated.zodName; | ||||||
|  | 		} | ||||||
|  | 		throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String optionalTypeZod(final Class<?> type) throws Exception { | ||||||
|  | 		if (type.isPrimitive()) { | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
|  | 		return ".optional()"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void createTablesSpecificType(final Field elem, final int fieldId, final StringBuilder builder, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		final String name = elem.getName(); | ||||||
|  | 		final Class<?> classModel = elem.getType(); | ||||||
|  | 		final int limitSize = AnnotationTools.getLimitSize(elem); | ||||||
|  |  | ||||||
|  | 		final String comment = AnnotationTools.getComment(elem); | ||||||
|  |  | ||||||
|  | 		if (fieldId != 0) { | ||||||
|  | 			builder.append(","); | ||||||
|  | 		} | ||||||
|  | 		if (comment != null) { | ||||||
|  | 			builder.append("\n\t// "); | ||||||
|  | 			builder.append(comment); | ||||||
|  | 		} | ||||||
|  | 		builder.append("\n\t"); | ||||||
|  | 		builder.append(name); | ||||||
|  | 		builder.append(": "); | ||||||
|  | 		builder.append(convertTypeZod(elem, previous)); | ||||||
|  | 		if (limitSize > 0 && classModel == String.class) { | ||||||
|  | 			builder.append(".max("); | ||||||
|  | 			builder.append(limitSize); | ||||||
|  | 			builder.append(")"); | ||||||
|  | 		} | ||||||
|  | 		if (AnnotationTools.getSchemaReadOnly(elem)) { | ||||||
|  | 			builder.append(".readonly()"); | ||||||
|  | 		} | ||||||
|  | 		builder.append(optionalTypeZod(classModel)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private static boolean isFieldFromSuperClass(final Class<?> model, final String filedName) { | ||||||
|  | 		final Class<?> superClass = model.getSuperclass(); | ||||||
|  | 		if (superClass == null) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		for (final Field field : superClass.getFields()) { | ||||||
|  | 			String name; | ||||||
|  | 			try { | ||||||
|  | 				name = AnnotationTools.getFieldName(field); | ||||||
|  | 				if (filedName.equals(name)) { | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  | 			} catch (final Exception e) { | ||||||
|  | 				// TODO Auto-generated catch block | ||||||
|  | 				LOGGER.trace("Catch error field name in parent create data table: {}", e.getMessage()); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static GeneratedTypes createBasicType() throws Exception { | ||||||
|  | 		final GeneratedTypes previous = new GeneratedTypes(); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Void.class, void.class }, "void", "void", null, null, true)); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { String.class }, "zod.string()", "string", null, "zod.string()", true)); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { InputStream.class, FormDataContentDisposition.class }, "z.instanceof(File)", "File", null, "z.instanceof(File)", true)); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Boolean.class, boolean.class }, "zod.boolean()", "boolean", null, "zod.boolean()", true)); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { UUID.class }, "ZodUUID", "UUID", "isUUID", "zod.string().uuid()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Long.class, long.class }, "ZodLong", "Long", "isLong", | ||||||
|  | 				// "zod.bigint()", | ||||||
|  | 				"zod.number()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Integer.class, int.class }, "ZodInteger", "Integer", "isInteger", "zod.number().safe()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Double.class, double.class }, "ZodDouble", "Double", "isDouble", "zod.number()", true), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Float.class, float.class }, "ZodFloat", "Float", "isFloat", "zod.number()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Instant.class }, "ZodInstant", "Instant", "isInstant", "zod.string()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Date.class }, "ZodDate", "Date", "isDate", "zod.date()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { Timestamp.class }, "ZodTimestamp", "Timestamp", "isTimestamp", "zod.date()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { LocalDate.class }, "ZodLocalDate", "LocalDate", "isLocalDate", "zod.date()", false), true); | ||||||
|  | 		previous.add(new ClassElement(new Class<?>[] { LocalTime.class }, "ZodLocalTime", "LocalTime", "isLocalTime", "zod.date()", false), true); | ||||||
|  | 		return previous; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** Request the generation of the TypeScript file for the "Zod" export model | ||||||
|  | 	 * @param classs List of class used in the model | ||||||
|  | 	 * @return A string representing the Server models | ||||||
|  | 	 * @throws Exception */ | ||||||
|  | 	public static String createTables(final List<Class<?>> classs) throws Exception { | ||||||
|  | 		return createTables(classs, createBasicType()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String createTables(final List<Class<?>> classs, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		for (final Class<?> clazz : classs) { | ||||||
|  | 			createTable(clazz, previous); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		final StringBuilder generatedData = new StringBuilder(); | ||||||
|  | 		generatedData.append(""" | ||||||
|  | 				/** | ||||||
|  | 				 * Interface of the server (auto-generated code) | ||||||
|  | 				 */ | ||||||
|  | 				import { z as zod } from \"zod\"; | ||||||
|  |  | ||||||
|  | 				"""); | ||||||
|  | 		for (final Class<?> elem : previous.order) { | ||||||
|  | 			final ClassElement data = previous.find(elem); | ||||||
|  | 			if (!data.nativeType) { | ||||||
|  | 				if (data.comment != null) { | ||||||
|  | 					generatedData.append(data.comment); | ||||||
|  | 				} | ||||||
|  | 				generatedData.append(createDeclaration(data)); | ||||||
|  | 				generatedData.append("\n\n"); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		LOGGER.info("generated: {}", generatedData.toString()); | ||||||
|  | 		return generatedData.toString(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static ClassElement createTable(final Class<?> clazz, final GeneratedTypes previous) throws Exception { | ||||||
|  | 		if (clazz == null) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		final ClassElement alreadyExist = previous.find(clazz); | ||||||
|  | 		if (previous.find(clazz) != null) { | ||||||
|  | 			return alreadyExist; | ||||||
|  | 		} | ||||||
|  | 		if (clazz.isPrimitive()) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		// add the current class to prevent multiple creation | ||||||
|  | 		final ClassElement curentElementClass = new ClassElement(clazz); | ||||||
|  | 		previous.add(curentElementClass); | ||||||
|  | 		// Local generation of class: | ||||||
|  | 		final StringBuilder internalBuilder = new StringBuilder(); | ||||||
|  | 		final List<String> alreadyAdded = new ArrayList<>(); | ||||||
|  | 		LOGGER.trace("parse class: '{}'", clazz.getCanonicalName()); | ||||||
|  | 		int fieldId = 0; | ||||||
|  | 		for (final Field elem : clazz.getFields()) { | ||||||
|  | 			// static field is only for internal global declaration ==> remove it .. | ||||||
|  | 			if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			final String dataName = elem.getName(); | ||||||
|  | 			if (isFieldFromSuperClass(clazz, dataName)) { | ||||||
|  | 				LOGGER.trace("        SKIP:  '{}'", elem.getName()); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (alreadyAdded.contains(dataName)) { | ||||||
|  | 				LOGGER.trace("        SKIP2: '{}'", elem.getName()); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			alreadyAdded.add(dataName); | ||||||
|  | 			LOGGER.trace("        + '{}'", elem.getName()); | ||||||
|  | 			if (false && DataAccess.isAddOnField(elem)) { | ||||||
|  | 				final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem); | ||||||
|  | 				LOGGER.error("Create type for: {} ==> {} (ADD-ON) ==> Not managed now ....", AnnotationTools.getFieldName(elem), elem.getType()); | ||||||
|  | 				/* LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); if (addOn != null) { addOn.createTables(tableName, elem, tmpOut, | ||||||
|  | 				 * preActionList, postActionList, createIfNotExist, createDrop, fieldId); } else { throw new DataAccessException( "Element matked as add-on but add-on does not loaded: table:" + | ||||||
|  | 				 * tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + elem.getType()); } fieldId++; */ | ||||||
|  | 			} else { | ||||||
|  | 				LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); | ||||||
|  | 				DataFactoryZod.createTablesSpecificType(elem, fieldId, internalBuilder, previous); | ||||||
|  | 				fieldId++; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  | 		final String description = AnnotationTools.getSchemaDescription(clazz); | ||||||
|  | 		final String example = AnnotationTools.getSchemaExample(clazz); | ||||||
|  | 		final StringBuilder generatedCommentedData = new StringBuilder(); | ||||||
|  | 		if (description != null || example != null) { | ||||||
|  | 			generatedCommentedData.append("/**\n"); | ||||||
|  | 			if (description != null) { | ||||||
|  | 				for (final String elem : description.split("\n")) { | ||||||
|  | 					generatedCommentedData.append(" * "); | ||||||
|  | 					generatedCommentedData.append(elem); | ||||||
|  | 					generatedCommentedData.append("\n"); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (example != null) { | ||||||
|  | 				generatedCommentedData.append(" * Example:\n"); | ||||||
|  | 				generatedCommentedData.append(" * ```\n"); | ||||||
|  | 				for (final String elem : example.split("\n")) { | ||||||
|  | 					generatedCommentedData.append(" * "); | ||||||
|  | 					generatedCommentedData.append(elem); | ||||||
|  | 					generatedCommentedData.append("\n"); | ||||||
|  | 				} | ||||||
|  | 				generatedCommentedData.append(" * ```\n"); | ||||||
|  | 			} | ||||||
|  | 			generatedCommentedData.append(" */\n"); | ||||||
|  | 		} | ||||||
|  | 		curentElementClass.comment = generatedCommentedData.toString(); | ||||||
|  | 		final StringBuilder generatedData = new StringBuilder(); | ||||||
|  | 		final Class<?> parentClass = clazz.getSuperclass(); | ||||||
|  | 		if (parentClass != null && parentClass != Object.class && parentClass != Record.class) { | ||||||
|  | 			final ClassElement parentDeclaration = createTable(parentClass, previous); | ||||||
|  | 			generatedData.append(parentDeclaration.zodName); | ||||||
|  | 			generatedData.append(".extend({"); | ||||||
|  | 		} else { | ||||||
|  | 			generatedData.append("zod.object({"); | ||||||
|  | 		} | ||||||
|  | 		generatedData.append(internalBuilder.toString()); | ||||||
|  | 		generatedData.append("\n})"); | ||||||
|  | 		// Remove the previous to reorder the map ==> parent must be inserted before us. | ||||||
|  | 		curentElementClass.declaration = generatedData.toString(); | ||||||
|  | 		previous.addOrder(curentElementClass); | ||||||
|  | 		return curentElementClass; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String createDeclaration(final ClassElement elem) { | ||||||
|  | 		final StringBuilder generatedData = new StringBuilder(); | ||||||
|  | 		if (elem.isEnum) { | ||||||
|  | 			generatedData.append("export enum "); | ||||||
|  | 			generatedData.append(elem.tsTypeName); | ||||||
|  | 			generatedData.append(" "); | ||||||
|  | 			generatedData.append(elem.declaration); | ||||||
|  | 			generatedData.append(";"); | ||||||
|  | 			generatedData.append("\nexport const "); | ||||||
|  | 			generatedData.append(elem.zodName); | ||||||
|  | 			generatedData.append(" = zod.nativeEnum("); | ||||||
|  | 			generatedData.append(elem.tsTypeName); | ||||||
|  | 			generatedData.append(");"); | ||||||
|  | 		} else { | ||||||
|  | 			generatedData.append("export const "); | ||||||
|  | 			generatedData.append(elem.zodName); | ||||||
|  | 			generatedData.append(" = "); | ||||||
|  | 			generatedData.append(elem.declaration); | ||||||
|  | 			generatedData.append(";"); | ||||||
|  | 			generatedData.append("\nexport type "); | ||||||
|  | 			generatedData.append(elem.tsTypeName); | ||||||
|  | 			generatedData.append(" = zod.infer<typeof "); | ||||||
|  | 			generatedData.append(elem.zodName); | ||||||
|  | 			generatedData.append(">;"); | ||||||
|  | 		} | ||||||
|  | 		// declare generic isXXX: | ||||||
|  | 		generatedData.append("\nexport function "); | ||||||
|  | 		generatedData.append(elem.tsCheckType); | ||||||
|  | 		generatedData.append("(data: any): data is "); | ||||||
|  | 		generatedData.append(elem.tsTypeName); | ||||||
|  | 		generatedData.append(" {\n\ttry {\n\t\t"); | ||||||
|  | 		generatedData.append(elem.zodName); | ||||||
|  | 		generatedData.append(""" | ||||||
|  | 				.parse(data); | ||||||
|  | 						return true; | ||||||
|  | 					} catch (e: any) { | ||||||
|  | 						console.log(`Fail to parse data ${e}`); | ||||||
|  | 						return false; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				"""); | ||||||
|  | 		return generatedData.toString(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void generatePackage(final List<Class<?>> classs, final String pathPackage) throws Exception { | ||||||
|  | 		final String packageApi = createTables(classs); | ||||||
|  | 		FileWriter myWriter = new FileWriter(pathPackage + File.separator + "model.ts"); | ||||||
|  | 		myWriter.write(packageApi.toString()); | ||||||
|  | 		myWriter.close(); | ||||||
|  | 		final String index = """ | ||||||
|  | 				/** | ||||||
|  | 				 * Global import of the package | ||||||
|  | 				 */ | ||||||
|  | 				export * from "./model.ts"; | ||||||
|  |  | ||||||
|  | 				"""; | ||||||
|  | 		myWriter = new FileWriter(pathPackage + File.separator + "index.ts"); | ||||||
|  | 		myWriter.write(index); | ||||||
|  | 		myWriter.close(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								src/org/kar/archidata/dataAccess/GroupBy.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/org/kar/archidata/dataAccess/GroupBy.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.sql.PreparedStatement; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public class GroupBy extends QueryOption { | ||||||
|  | 	protected final List<String> childs; | ||||||
|  |  | ||||||
|  | 	public GroupBy(final List<String> childs) { | ||||||
|  | 		this.childs = childs; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public GroupBy(final String... childs) { | ||||||
|  | 		this.childs = List.of(childs); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
|  | 		if (this.childs.size() == 0) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		query.append(" GROUP BY "); | ||||||
|  | 		boolean first = true; | ||||||
|  | 		for (final String elem : this.childs) { | ||||||
|  | 			if (first) { | ||||||
|  | 				first = false; | ||||||
|  | 			} else { | ||||||
|  | 				query.append(", "); | ||||||
|  | 			} | ||||||
|  | 			// query.append("`"); | ||||||
|  | 			query.append(elem); | ||||||
|  | 			// query.append("` "); | ||||||
|  | 		} | ||||||
|  | 		query.append("\n"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception { | ||||||
|  | 		// nothing to add. | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -10,7 +10,7 @@ public class Limit extends QueryOption { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void generateQuerry(final StringBuilder query, final String tableName) { | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
| 		query.append(" LIMIT ? "); | 		query.append(" LIMIT ? \n"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception { | 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception { | ||||||
|   | |||||||
| @@ -15,9 +15,10 @@ public class OrderBy extends QueryOption { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void generateQuerry(final StringBuilder query, final String tableName) { | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
| 		if (this.childs.size() >= 1) { | 		if (this.childs.size() == 0) { | ||||||
| 			query.append(" ORDER BY "); | 			return; | ||||||
| 		} | 		} | ||||||
|  | 		query.append(" ORDER BY "); | ||||||
| 		boolean first = true; | 		boolean first = true; | ||||||
| 		for (final OrderItem elem : this.childs) { | 		for (final OrderItem elem : this.childs) { | ||||||
| 			if (first) { | 			if (first) { | ||||||
| @@ -25,14 +26,13 @@ public class OrderBy extends QueryOption { | |||||||
| 			} else { | 			} else { | ||||||
| 				query.append(", "); | 				query.append(", "); | ||||||
| 			} | 			} | ||||||
| 			query.append("`"); | 			// query.append("`"); | ||||||
| 			query.append(elem.value); | 			query.append(elem.value); | ||||||
| 			query.append("` "); | 			// query.append("`"); | ||||||
|  | 			query.append(" "); | ||||||
| 			query.append(elem.order.toString()); | 			query.append(elem.order.toString()); | ||||||
| 		} | 		} | ||||||
| 		if (this.childs.size() >= 1) { | 		query.append("\n"); | ||||||
| 			query.append(")"); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception { | 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception { | ||||||
|   | |||||||
| @@ -17,6 +17,10 @@ public class QueryAnd implements QueryItem { | |||||||
| 		Collections.addAll(this.childs, items); | 		Collections.addAll(this.childs, items); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public void add(final QueryItem... items) { | ||||||
|  | 		Collections.addAll(this.childs, items); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void generateQuerry(final StringBuilder query, final String tableName) { | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
| 		if (this.childs.size() >= 1) { | 		if (this.childs.size() >= 1) { | ||||||
| @@ -43,4 +47,8 @@ public class QueryAnd implements QueryItem { | |||||||
| 			elem.injectQuerry(ps, iii); | 			elem.injectQuerry(ps, iii); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public int size() { | ||||||
|  | 		return this.childs.size(); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,8 +15,10 @@ public class QueryCondition implements QueryItem { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void generateQuerry(final StringBuilder query, final String tableName) { | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
|  | 		if (tableName != null) { | ||||||
| 			query.append(tableName); | 			query.append(tableName); | ||||||
| 			query.append("."); | 			query.append("."); | ||||||
|  | 		} | ||||||
| 		query.append(this.key); | 		query.append(this.key); | ||||||
| 		query.append(" "); | 		query.append(" "); | ||||||
| 		query.append(this.comparator); | 		query.append(this.comparator); | ||||||
|   | |||||||
| @@ -24,8 +24,10 @@ public class QueryInList<T> implements QueryItem { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void generateQuerry(final StringBuilder query, final String tableName) { | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
|  | 		if (tableName != null) { | ||||||
| 			query.append(tableName); | 			query.append(tableName); | ||||||
| 			query.append("."); | 			query.append("."); | ||||||
|  | 		} | ||||||
| 		query.append(this.key); | 		query.append(this.key); | ||||||
| 		query.append(" "); | 		query.append(" "); | ||||||
| 		query.append(this.comparator); | 		query.append(this.comparator); | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								src/org/kar/archidata/dataAccess/QueryNotNull.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/org/kar/archidata/dataAccess/QueryNotNull.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.sql.PreparedStatement; | ||||||
|  |  | ||||||
|  | public class QueryNotNull implements QueryItem { | ||||||
|  | 	private final String key; | ||||||
|  |  | ||||||
|  | 	public QueryNotNull(final String key) { | ||||||
|  | 		this.key = key; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
|  | 		if (tableName != null) { | ||||||
|  | 			query.append(tableName); | ||||||
|  | 			query.append("."); | ||||||
|  | 		} | ||||||
|  | 		query.append(this.key); | ||||||
|  | 		query.append(" IS NOT NULL"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {} | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/org/kar/archidata/dataAccess/QueryNull.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/org/kar/archidata/dataAccess/QueryNull.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.sql.PreparedStatement; | ||||||
|  |  | ||||||
|  | public class QueryNull implements QueryItem { | ||||||
|  | 	private final String key; | ||||||
|  |  | ||||||
|  | 	public QueryNull(final String key) { | ||||||
|  | 		this.key = key; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public void generateQuerry(final StringBuilder query, final String tableName) { | ||||||
|  | 		if (tableName != null) { | ||||||
|  | 			query.append(tableName); | ||||||
|  | 			query.append("."); | ||||||
|  | 		} | ||||||
|  | 		query.append(this.key); | ||||||
|  | 		query.append(" IS NULL"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public void injectQuerry(final PreparedStatement ps, final CountInOut iii) throws Exception {} | ||||||
|  | } | ||||||
| @@ -64,5 +64,4 @@ public class QueryOptions { | |||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								src/org/kar/archidata/dataAccess/RetreiveFromDB.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/org/kar/archidata/dataAccess/RetreiveFromDB.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | package org.kar.archidata.dataAccess; | ||||||
|  |  | ||||||
|  | import java.sql.ResultSet; | ||||||
|  |  | ||||||
|  | public interface RetreiveFromDB { | ||||||
|  | 	void doRequest(final ResultSet rs, Object obj) throws Exception; | ||||||
|  | } | ||||||
| @@ -1,22 +1,32 @@ | |||||||
| package org.kar.archidata.dataAccess.addOn; | package org.kar.archidata.dataAccess.addOn; | ||||||
|  |  | ||||||
| import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||||
|  | import java.lang.reflect.ParameterizedType; | ||||||
| import java.sql.PreparedStatement; | import java.sql.PreparedStatement; | ||||||
| import java.sql.ResultSet; | import java.sql.ResultSet; | ||||||
| import java.sql.Types; | import java.sql.Types; | ||||||
|  | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.AnnotationTools; | import org.kar.archidata.annotation.AnnotationTools; | ||||||
| import org.kar.archidata.annotation.DataJson; | import org.kar.archidata.annotation.DataJson; | ||||||
| import org.kar.archidata.dataAccess.CountInOut; | import org.kar.archidata.dataAccess.CountInOut; | ||||||
|  | import org.kar.archidata.dataAccess.DataAccess; | ||||||
| import org.kar.archidata.dataAccess.DataAccessAddOn; | import org.kar.archidata.dataAccess.DataAccessAddOn; | ||||||
| import org.kar.archidata.dataAccess.DataFactory; | import org.kar.archidata.dataAccess.DataFactory; | ||||||
| import org.kar.archidata.dataAccess.LazyGetter; | import org.kar.archidata.dataAccess.LazyGetter; | ||||||
| import org.kar.archidata.dataAccess.QueryOptions; | import org.kar.archidata.dataAccess.QueryOptions; | ||||||
|  | import org.kar.archidata.dataAccess.addOn.model.TableCoversLongLong; | ||||||
|  | import org.kar.archidata.dataAccess.addOn.model.TableCoversLongUUID; | ||||||
|  | import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDLong; | ||||||
|  | import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDUUID; | ||||||
|  | import org.kar.archidata.dataAccess.options.OverrideTableName; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| import com.fasterxml.jackson.annotation.JsonValue; | import com.fasterxml.jackson.annotation.JsonValue; | ||||||
|  | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  |  | ||||||
| import jakarta.validation.constraints.NotNull; | import jakarta.validation.constraints.NotNull; | ||||||
| @@ -85,6 +95,46 @@ public class AddOnDataJson implements DataAccessAddOn { | |||||||
| 		count.inc(); | 		count.inc(); | ||||||
| 		if (!rs.wasNull()) { | 		if (!rs.wasNull()) { | ||||||
| 			final ObjectMapper objectMapper = new ObjectMapper(); | 			final ObjectMapper objectMapper = new ObjectMapper(); | ||||||
|  | 			if (field.getType() == List.class) { | ||||||
|  | 				final ParameterizedType listType = (ParameterizedType) field.getGenericType(); | ||||||
|  | 				final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0]; | ||||||
|  | 				if (listClass == Long.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				if (listClass == Float.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				if (listClass == Double.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				if (listClass == Integer.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				if (listClass == Short.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				if (listClass == String.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				if (listClass == UUID.class) { | ||||||
|  | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});// field.getType()); | ||||||
|  | 					field.set(data, dataParsed); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName()); | ||||||
|  | 			} | ||||||
| 			final Object dataParsed = objectMapper.readValue(jsonData, field.getType()); | 			final Object dataParsed = objectMapper.readValue(jsonData, field.getType()); | ||||||
| 			field.set(data, dataParsed); | 			field.set(data, dataParsed); | ||||||
| 		} | 		} | ||||||
| @@ -95,4 +145,137 @@ public class AddOnDataJson implements DataAccessAddOn { | |||||||
| 			final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { | 			final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { | ||||||
| 		DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class); | 		DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public static void addLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			data.covers = new ArrayList<>(); | ||||||
|  | 		} | ||||||
|  | 		for (final Long elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		data.covers.add(remoteKey); | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void addLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			data.covers = new ArrayList<>(); | ||||||
|  | 		} | ||||||
|  | 		for (final UUID elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		data.covers.add(remoteKey); | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void addLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			data.covers = new ArrayList<>(); | ||||||
|  | 		} | ||||||
|  | 		for (final UUID elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		data.covers.add(remoteKey); | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void addLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			data.covers = new ArrayList<>(); | ||||||
|  | 		} | ||||||
|  | 		for (final Long elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		data.covers.add(remoteKey); | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void removeLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		final List<Long> newList = new ArrayList<>(); | ||||||
|  | 		for (final Long elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			newList.add(elem); | ||||||
|  | 		} | ||||||
|  | 		data.covers = newList; | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void removeLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		final List<UUID> newList = new ArrayList<>(); | ||||||
|  | 		for (final UUID elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			newList.add(elem); | ||||||
|  | 		} | ||||||
|  | 		data.covers = newList; | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void removeLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		final List<Long> newList = new ArrayList<>(); | ||||||
|  | 		for (final Long elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			newList.add(elem); | ||||||
|  | 		} | ||||||
|  | 		data.covers = newList; | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void removeLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey) throws Exception { | ||||||
|  | 		final String tableName = AnnotationTools.getTableName(clazz); | ||||||
|  | 		final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id, new OverrideTableName(tableName)); | ||||||
|  | 		if (data.covers == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		final List<UUID> newList = new ArrayList<>(); | ||||||
|  | 		for (final UUID elem : data.covers) { | ||||||
|  | 			if (elem.equals(remoteKey)) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			newList.add(elem); | ||||||
|  | 		} | ||||||
|  | 		data.covers = newList; | ||||||
|  | 		DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName)); | ||||||
|  | 	} | ||||||
|  | 	/* public static <TYPE> void addLink(final Class<TYPE> clazz, final Object localKey, final String column, final Object remoteKey) throws Exception { final String tableName = | ||||||
|  | 	 * AnnotationTools.getTableName(clazz); final TYPE data = DataAccess.get(clazz, localKey); // TODO: add filter of the "column" // find the field column: // add the remoteKey in the list: // post | ||||||
|  | 	 * new data in the DB final String linkTableName = generateLinkTableName(this.tableName, this.column); final LinkTable insertElement = new LinkTable(this.localKey, this.remoteKey); | ||||||
|  | 	 * DataAccess.insert(insertElement, new OverrideTableName(linkTableName)); } */ | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import java.sql.PreparedStatement; | |||||||
| import java.sql.ResultSet; | import java.sql.ResultSet; | ||||||
| import java.sql.Types; | import java.sql.Types; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.AnnotationTools; | import org.kar.archidata.annotation.AnnotationTools; | ||||||
| import org.kar.archidata.dataAccess.CountInOut; | import org.kar.archidata.dataAccess.CountInOut; | ||||||
| @@ -14,6 +15,7 @@ import org.kar.archidata.dataAccess.DataFactory; | |||||||
| import org.kar.archidata.dataAccess.LazyGetter; | import org.kar.archidata.dataAccess.LazyGetter; | ||||||
| import org.kar.archidata.dataAccess.QueryOptions; | import org.kar.archidata.dataAccess.QueryOptions; | ||||||
| import org.kar.archidata.exception.DataAccessException; | import org.kar.archidata.exception.DataAccessException; | ||||||
|  | import org.kar.archidata.tools.UuidUtils; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| @@ -51,10 +53,33 @@ public class AddOnManyToOne implements DataAccessAddOn { | |||||||
| 	public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws Exception { | 	public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) throws Exception { | ||||||
| 		final Object data = field.get(rootObject); | 		final Object data = field.get(rootObject); | ||||||
| 		if (data == null) { | 		if (data == null) { | ||||||
|  | 			if (field.getType() == Long.class) { | ||||||
| 				ps.setNull(iii.value, Types.BIGINT); | 				ps.setNull(iii.value, Types.BIGINT); | ||||||
|  | 			} else if (field.getType() == Integer.class) { | ||||||
|  | 				ps.setNull(iii.value, Types.INTEGER); | ||||||
|  | 			} else if (field.getType() == Short.class) { | ||||||
|  | 				ps.setNull(iii.value, Types.INTEGER); | ||||||
|  | 			} else if (field.getType() == String.class) { | ||||||
|  | 				ps.setNull(iii.value, Types.VARCHAR); | ||||||
|  | 			} else if (field.getType() == UUID.class) { | ||||||
|  | 				ps.setNull(iii.value, Types.BINARY); | ||||||
|  | 			} | ||||||
| 		} else if (field.getType() == Long.class) { | 		} else if (field.getType() == Long.class) { | ||||||
| 			final Long dataLong = (Long) data; | 			final Long dataTyped = (Long) data; | ||||||
| 			ps.setLong(iii.value, dataLong); | 			ps.setLong(iii.value, dataTyped); | ||||||
|  | 		} else if (field.getType() == Integer.class) { | ||||||
|  | 			final Integer dataTyped = (Integer) data; | ||||||
|  | 			ps.setInt(iii.value, dataTyped); | ||||||
|  | 		} else if (field.getType() == Short.class) { | ||||||
|  | 			final Short dataTyped = (Short) data; | ||||||
|  | 			ps.setShort(iii.value, dataTyped); | ||||||
|  | 		} else if (field.getType() == String.class) { | ||||||
|  | 			final String dataTyped = (String) data; | ||||||
|  | 			ps.setString(iii.value, dataTyped); | ||||||
|  | 		} else if (field.getType() == UUID.class) { | ||||||
|  | 			final UUID dataTyped = (UUID) data; | ||||||
|  | 			final byte[] dataByte = UuidUtils.asBytes(dataTyped); | ||||||
|  | 			ps.setBytes(iii.value, dataByte); | ||||||
| 		} else { | 		} else { | ||||||
| 			final Field idField = AnnotationTools.getFieldOfId(field.getType()); | 			final Field idField = AnnotationTools.getFieldOfId(field.getType()); | ||||||
| 			final Object uid = idField.get(data); | 			final Object uid = idField.get(data); | ||||||
| @@ -71,7 +96,11 @@ public class AddOnManyToOne implements DataAccessAddOn { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public boolean canInsert(final Field field) { | 	public boolean canInsert(final Field field) { | ||||||
| 		if (field.getType() == Long.class) { | 		if (field.getType() == Long.class | ||||||
|  | 				|| field.getType() == Integer.class | ||||||
|  | 				|| field.getType() == Short.class | ||||||
|  | 				|| field.getType() == String.class | ||||||
|  | 				|| field.getType() == UUID.class) { | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 		final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); | 		final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); | ||||||
| @@ -88,7 +117,11 @@ public class AddOnManyToOne implements DataAccessAddOn { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public boolean canRetrieve(final Field field) { | 	public boolean canRetrieve(final Field field) { | ||||||
| 		if (field.getType() == Long.class) { | 		if (field.getType() == Long.class | ||||||
|  | 				|| field.getType() == Integer.class | ||||||
|  | 				|| field.getType() == Short.class | ||||||
|  | 				|| field.getType() == String.class | ||||||
|  | 				|| field.getType() == UUID.class) { | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 		final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); | 		final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); | ||||||
| @@ -101,7 +134,11 @@ public class AddOnManyToOne implements DataAccessAddOn { | |||||||
| 	@Override | 	@Override | ||||||
| 	public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name, | 	public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name, | ||||||
| 			@NotNull final CountInOut elemCount, final QueryOptions options) throws Exception { | 			@NotNull final CountInOut elemCount, final QueryOptions options) throws Exception { | ||||||
| 		if (field.getType() == Long.class) { | 		if (field.getType() == Long.class | ||||||
|  | 				|| field.getType() == Integer.class | ||||||
|  | 				|| field.getType() == Short.class | ||||||
|  | 				|| field.getType() == String.class | ||||||
|  | 				|| field.getType() == UUID.class) { | ||||||
| 			querrySelect.append(" "); | 			querrySelect.append(" "); | ||||||
| 			querrySelect.append(tableName); | 			querrySelect.append(tableName); | ||||||
| 			querrySelect.append("."); | 			querrySelect.append("."); | ||||||
| @@ -150,6 +187,39 @@ public class AddOnManyToOne implements DataAccessAddOn { | |||||||
| 			} | 			} | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  | 		if (field.getType() == Integer.class) { | ||||||
|  | 			final Integer foreignKey = rs.getInt(count.value); | ||||||
|  | 			count.inc(); | ||||||
|  | 			if (!rs.wasNull()) { | ||||||
|  | 				field.set(data, foreignKey); | ||||||
|  | 			} | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		if (field.getType() == Short.class) { | ||||||
|  | 			final Short foreignKey = rs.getShort(count.value); | ||||||
|  | 			count.inc(); | ||||||
|  | 			if (!rs.wasNull()) { | ||||||
|  | 				field.set(data, foreignKey); | ||||||
|  | 			} | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		if (field.getType() == String.class) { | ||||||
|  | 			final String foreignKey = rs.getString(count.value); | ||||||
|  | 			count.inc(); | ||||||
|  | 			if (!rs.wasNull()) { | ||||||
|  | 				field.set(data, foreignKey); | ||||||
|  | 			} | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		if (field.getType() == UUID.class) { | ||||||
|  | 			final byte[] tmp = rs.getBytes(count.value); | ||||||
|  | 			count.inc(); | ||||||
|  | 			if (!rs.wasNull()) { | ||||||
|  | 				final UUID foreignKey = UuidUtils.asUuid(tmp); | ||||||
|  | 				field.set(data, foreignKey); | ||||||
|  | 			} | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		final Class<?> objectClass = field.getType(); | 		final Class<?> objectClass = field.getType(); | ||||||
| 		final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); | 		final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); | ||||||
| 		if (decorators == null) { | 		if (decorators == null) { | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public boolean canInsert(final Field field) { | 	public boolean canInsert(final Field field) { | ||||||
| 		return false; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @@ -83,7 +83,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public boolean canRetrieve(final Field field) { | 	public boolean canRetrieve(final Field field) { | ||||||
| 		return false; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
|   | |||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | package org.kar.archidata.dataAccess.addOn.model; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.annotation.DataJson; | ||||||
|  | import org.kar.archidata.model.GenericData; | ||||||
|  |  | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.persistence.Id; | ||||||
|  |  | ||||||
|  | public class TableCoversLongLong extends GenericData { | ||||||
|  | 	public TableCoversLongLong() { | ||||||
|  | 		// nothing to do... | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public TableCoversLongLong(final Long id, final List<Long> covers) { | ||||||
|  | 		this.id = id; | ||||||
|  | 		this.covers = covers; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@Id | ||||||
|  | 	public Long id; | ||||||
|  | 	@DataJson() | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	public List<Long> covers; | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package org.kar.archidata.dataAccess.addOn.model; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.annotation.DataJson; | ||||||
|  | import org.kar.archidata.model.GenericData; | ||||||
|  |  | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.persistence.Id; | ||||||
|  |  | ||||||
|  | public class TableCoversLongUUID extends GenericData { | ||||||
|  | 	public TableCoversLongUUID() { | ||||||
|  | 		// nothing to do... | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public TableCoversLongUUID(final Long id, final List<UUID> covers) { | ||||||
|  | 		this.id = id; | ||||||
|  | 		this.covers = covers; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@Id | ||||||
|  | 	public Long id; | ||||||
|  | 	@DataJson() | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	public List<UUID> covers; | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package org.kar.archidata.dataAccess.addOn.model; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.annotation.DataJson; | ||||||
|  | import org.kar.archidata.model.GenericData; | ||||||
|  |  | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.persistence.Id; | ||||||
|  |  | ||||||
|  | public class TableCoversUUIDLong extends GenericData { | ||||||
|  | 	public TableCoversUUIDLong() { | ||||||
|  | 		// nothing to do... | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public TableCoversUUIDLong(final UUID id, final List<Long> covers) { | ||||||
|  | 		this.id = id; | ||||||
|  | 		this.covers = covers; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@Id | ||||||
|  | 	public UUID id; | ||||||
|  | 	@DataJson() | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	public List<Long> covers; | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package org.kar.archidata.dataAccess.addOn.model; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.annotation.DataJson; | ||||||
|  | import org.kar.archidata.model.GenericData; | ||||||
|  |  | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.persistence.Id; | ||||||
|  |  | ||||||
|  | public class TableCoversUUIDUUID extends GenericData { | ||||||
|  | 	public TableCoversUUIDUUID() { | ||||||
|  | 		// nothing to do... | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public TableCoversUUIDUUID(final UUID id, final List<UUID> covers) { | ||||||
|  | 		this.id = id; | ||||||
|  | 		this.covers = covers; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@Id | ||||||
|  | 	public UUID id; | ||||||
|  | 	@DataJson() | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	public List<UUID> covers; | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								src/org/kar/archidata/dataAccess/exportTools/TableQuery.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/org/kar/archidata/dataAccess/exportTools/TableQuery.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | package org.kar.archidata.dataAccess.exportTools; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public class TableQuery { | ||||||
|  |  | ||||||
|  | 	public final List<TableQueryTypes> headers; | ||||||
|  | 	public final List<List<Object>> values = new ArrayList<>(); | ||||||
|  |  | ||||||
|  | 	public TableQuery(final List<TableQueryTypes> headers) { | ||||||
|  | 		this.headers = headers; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | package org.kar.archidata.dataAccess.exportTools; | ||||||
|  |  | ||||||
|  | public class TableQueryTypes { | ||||||
|  |  | ||||||
|  | 	public Class<?> type; | ||||||
|  | 	public String name; | ||||||
|  | 	public String title; | ||||||
|  |  | ||||||
|  | 	public TableQueryTypes(final Class<?> type, final String name, final String title) { | ||||||
|  | 		this.type = type; | ||||||
|  | 		this.name = name; | ||||||
|  | 		this.title = title; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public TableQueryTypes(final Class<?> type, final String name) { | ||||||
|  | 		this.type = type; | ||||||
|  | 		this.name = name; | ||||||
|  | 		this.title = name; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -43,13 +43,12 @@ public class Condition extends QueryOption { | |||||||
| 				query.append(tableName); | 				query.append(tableName); | ||||||
| 				query.append("."); | 				query.append("."); | ||||||
| 				query.append(deletedFieldName); | 				query.append(deletedFieldName); | ||||||
| 				query.append(" = false "); | 				query.append(" = false \n"); | ||||||
| 			} | 			} | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		query.append(" WHERE ("); | 		query.append(" WHERE ("); | ||||||
| 		this.condition.generateQuerry(query, tableName); | 		this.condition.generateQuerry(query, tableName); | ||||||
|  |  | ||||||
| 		query.append(") "); | 		query.append(") "); | ||||||
| 		if (exclude_deleted && deletedFieldName != null) { | 		if (exclude_deleted && deletedFieldName != null) { | ||||||
| 			query.append("AND "); | 			query.append("AND "); | ||||||
| @@ -58,5 +57,6 @@ public class Condition extends QueryOption { | |||||||
| 			query.append(deletedFieldName); | 			query.append(deletedFieldName); | ||||||
| 			query.append(" = false "); | 			query.append(" = false "); | ||||||
| 		} | 		} | ||||||
|  | 		query.append("\n"); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,48 @@ | |||||||
|  | package org.kar.archidata.dataAccess.options; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.GlobalConfiguration; | ||||||
|  | import org.kar.archidata.dataAccess.QueryOption; | ||||||
|  | import org.kar.archidata.dataAccess.QueryOptions; | ||||||
|  | import org.kar.archidata.db.DBConfig; | ||||||
|  | import org.kar.archidata.db.DBEntry; | ||||||
|  |  | ||||||
|  | public class DBInterfaceOption extends QueryOption { | ||||||
|  | 	private DBEntry entry = null; | ||||||
|  | 	private final DBConfig config; | ||||||
|  | 	private final boolean root; | ||||||
|  |  | ||||||
|  | 	public DBInterfaceOption(final DBConfig config) { | ||||||
|  | 		this.config = config; | ||||||
|  | 		this.root = false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public DBInterfaceOption(final DBConfig config, boolean root) { | ||||||
|  | 		this.config = config; | ||||||
|  | 		this.root = root; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public DBEntry getEntry(QueryOptions options) throws IOException { | ||||||
|  | 		if (this.entry == null) { | ||||||
|  | 			final DBInterfaceRoot isRoot = options.get(DBInterfaceRoot.class); | ||||||
|  | 			this.entry = DBEntry.createInterface(this.config, isRoot != null && isRoot.getRoot()); | ||||||
|  | 		} | ||||||
|  | 		return this.entry; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public boolean getRoot() { | ||||||
|  | 		return this.root; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static DBEntry getAutoEntry(QueryOptions options) throws IOException { | ||||||
|  | 		final DBInterfaceOption dbOption = options.get(DBInterfaceOption.class); | ||||||
|  | 		if (dbOption == null) { | ||||||
|  | 			final DBInterfaceRoot isRoot = options.get(DBInterfaceRoot.class); | ||||||
|  | 			return DBEntry.createInterface(GlobalConfiguration.dbConfig, isRoot != null && isRoot.getRoot()); | ||||||
|  | 		} else { | ||||||
|  | 			return dbOption.getEntry(options); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | package org.kar.archidata.dataAccess.options; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.dataAccess.QueryOption; | ||||||
|  |  | ||||||
|  | public class DBInterfaceRoot extends QueryOption { | ||||||
|  | 	private final boolean root; | ||||||
|  |  | ||||||
|  | 	public DBInterfaceRoot(boolean root) { | ||||||
|  | 		this.root = root; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public boolean getRoot() { | ||||||
|  | 		return this.root; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -52,7 +52,7 @@ public class DBEntry implements Closeable { | |||||||
| 		try { | 		try { | ||||||
| 			this.connection = DriverManager.getConnection(this.config.getUrl(true), this.config.getLogin(), this.config.getPassword()); | 			this.connection = DriverManager.getConnection(this.config.getUrl(true), this.config.getLogin(), this.config.getPassword()); | ||||||
| 		} catch (final SQLException ex) { | 		} catch (final SQLException ex) { | ||||||
| 			throw new IOException("Connection db fail: " + ex.getMessage()); | 			throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| @@ -61,7 +61,7 @@ public class DBEntry implements Closeable { | |||||||
| 		try { | 		try { | ||||||
| 			this.connection = DriverManager.getConnection(this.config.getUrl(), this.config.getLogin(), this.config.getPassword()); | 			this.connection = DriverManager.getConnection(this.config.getUrl(), this.config.getLogin(), this.config.getPassword()); | ||||||
| 		} catch (final SQLException ex) { | 		} catch (final SQLException ex) { | ||||||
| 			throw new IOException("Connection db fail: " + ex.getMessage()); | 			throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import java.util.UUID; | |||||||
| public class RESTErrorResponseExeption extends Exception { | public class RESTErrorResponseExeption extends Exception { | ||||||
| 	public UUID uuid; | 	public UUID uuid; | ||||||
| 	public String time; | 	public String time; | ||||||
| 	public String error; | 	public String name; | ||||||
| 	public String message; | 	public String message; | ||||||
| 	public int status; | 	public int status; | ||||||
| 	public String statusMessage; | 	public String statusMessage; | ||||||
| @@ -13,16 +13,16 @@ public class RESTErrorResponseExeption extends Exception { | |||||||
| 	public RESTErrorResponseExeption() { | 	public RESTErrorResponseExeption() { | ||||||
| 		this.uuid = null; | 		this.uuid = null; | ||||||
| 		this.time = null; | 		this.time = null; | ||||||
| 		this.error = null; | 		this.name = null; | ||||||
| 		this.message = null; | 		this.message = null; | ||||||
| 		this.status = 0; | 		this.status = 0; | ||||||
| 		this.statusMessage = null; | 		this.statusMessage = null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public RESTErrorResponseExeption(final UUID uuid, final String time, final String error, final String message, final int status, final String statusMessage) { | 	public RESTErrorResponseExeption(final UUID uuid, final String time, final String name, final String message, final int status, final String statusMessage) { | ||||||
| 		this.uuid = uuid; | 		this.uuid = uuid; | ||||||
| 		this.time = time; | 		this.time = time; | ||||||
| 		this.error = error; | 		this.name = name; | ||||||
| 		this.message = message; | 		this.message = message; | ||||||
| 		this.status = status; | 		this.status = status; | ||||||
| 		this.statusMessage = statusMessage; | 		this.statusMessage = statusMessage; | ||||||
| @@ -30,7 +30,7 @@ public class RESTErrorResponseExeption extends Exception { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public String toString() { | 	public String toString() { | ||||||
| 		return "RESTErrorResponseExeption [uuid=" + this.uuid + ", time=" + this.time + ", error=" + this.error + ", message=" + this.message + ", status=" + this.status + ", statusMessage=" | 		return "RESTErrorResponseExeption [uuid=" + this.uuid + ", time=" + this.time + ", name=" + this.name + ", message=" + this.message + ", status=" + this.status + ", statusMessage=" | ||||||
| 				+ this.statusMessage + "]"; | 				+ this.statusMessage + "]"; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,8 +43,8 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 	private ResourceInfo resourceInfo; | 	private ResourceInfo resourceInfo; | ||||||
| 	protected final String applicationName; | 	protected final String applicationName; | ||||||
|  |  | ||||||
| 	private static final String AUTHENTICATION_SCHEME = "Yota"; | 	public static final String AUTHENTICATION_SCHEME = "Bearer"; | ||||||
| 	private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota"; | 	public static final String APIKEY = "ApiKey"; | ||||||
|  |  | ||||||
| 	public AuthenticationFilter(final String applicationName) { | 	public AuthenticationFilter(final String applicationName) { | ||||||
| 		this.applicationName = applicationName; | 		this.applicationName = applicationName; | ||||||
| @@ -58,7 +58,7 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 		// Access denied for all | 		// Access denied for all | ||||||
| 		if (method.isAnnotationPresent(DenyAll.class)) { | 		if (method.isAnnotationPresent(DenyAll.class)) { | ||||||
| 			LOGGER.debug("   ==> deny all {}", requestContext.getUriInfo().getPath()); | 			LOGGER.debug("   ==> deny all {}", requestContext.getUriInfo().getPath()); | ||||||
| 			requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build()); | 			abortWithForbidden(requestContext, "Access blocked !!!"); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -71,28 +71,28 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 		// this is a security guard, all the API must define their access level: | 		// this is a security guard, all the API must define their access level: | ||||||
| 		if (!method.isAnnotationPresent(RolesAllowed.class)) { | 		if (!method.isAnnotationPresent(RolesAllowed.class)) { | ||||||
| 			LOGGER.error("   ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath()); | 			LOGGER.error("   ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath()); | ||||||
| 			requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build()); | 			abortWithForbidden(requestContext, "Access ILLEGAL !!!"); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Get the Authorization header from the request | 		// Get the Authorization header from the request | ||||||
| 		String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); | 		String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); | ||||||
|  | 		String apikeyHeader = requestContext.getHeaderString(APIKEY); | ||||||
| 		// logger.debug("authorizationHeader: {}", authorizationHeader); | 		// logger.debug("authorizationHeader: {}", authorizationHeader); | ||||||
| 		if (authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) { | 		if (authorizationHeader == null && apikeyHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) { | ||||||
| 			final MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters(); | 			final MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters(); | ||||||
| 			for (final Entry<String, List<String>> item : quaryparam.entrySet()) { | 			for (final Entry<String, List<String>> item : quaryparam.entrySet()) { | ||||||
| 				if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) { | 				if ((authorizationHeader == null && HttpHeaders.AUTHORIZATION.equals(item.getKey())) && !item.getValue().isEmpty()) { | ||||||
| 					if (!item.getValue().isEmpty()) { |  | ||||||
| 					authorizationHeader = item.getValue().get(0); | 					authorizationHeader = item.getValue().get(0); | ||||||
| 				} | 				} | ||||||
| 					break; | 				if ((apikeyHeader == null && APIKEY.equals(item.getKey())) && !item.getValue().isEmpty()) { | ||||||
|  | 					apikeyHeader = item.getValue().get(0); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		// logger.debug("authorizationHeader: {}", authorizationHeader); | 		// logger.debug("authorizationHeader: {}", authorizationHeader); | ||||||
| 		final boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader); | 		final boolean isApplicationToken = apikeyHeader != null; | ||||||
| 		final boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader); | 		final boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader); | ||||||
| 		// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)" |  | ||||||
| 		if (!isApplicationToken && !isJwtToken) { | 		if (!isApplicationToken && !isJwtToken) { | ||||||
| 			LOGGER.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath()); | 			LOGGER.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath()); | ||||||
| 			abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath()); | 			abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath()); | ||||||
| @@ -100,7 +100,7 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 		} | 		} | ||||||
| 		UserByToken userByToken = null; | 		UserByToken userByToken = null; | ||||||
| 		if (isJwtToken) { | 		if (isJwtToken) { | ||||||
| 			// Extract the token from the Authorization header (Remove "Yota ") | 			// Extract the token from the Authorization header (Remove "Bearer ") | ||||||
| 			final String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim(); | 			final String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim(); | ||||||
| 			// logger.debug("token: {}", token); | 			// logger.debug("token: {}", token); | ||||||
| 			try { | 			try { | ||||||
| @@ -116,9 +116,7 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			// Extract the token from the Authorization header (Remove "Zota ") | 			final String token = apikeyHeader.trim(); | ||||||
| 			final String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim(); |  | ||||||
| 			// logger.debug("token: {}", token); |  | ||||||
| 			try { | 			try { | ||||||
| 				userByToken = validateToken(token); | 				userByToken = validateToken(token); | ||||||
| 			} catch (final Exception e) { | 			} catch (final Exception e) { | ||||||
| @@ -164,13 +162,6 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 		return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " "); | 		return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " "); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private boolean isApplicationTokenBasedAuthentication(final String authorizationHeader) { |  | ||||||
| 		// Check if the Authorization header is valid |  | ||||||
| 		// It must not be null and must be prefixed with "Bearer" plus a whitespace |  | ||||||
| 		// The authentication scheme comparison must be case-insensitive |  | ||||||
| 		return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " "); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void abortWithUnauthorized(final ContainerRequestContext requestContext, final String message) { | 	private void abortWithUnauthorized(final ContainerRequestContext requestContext, final String message) { | ||||||
|  |  | ||||||
| 		// Abort the filter chain with a 401 status code response | 		// Abort the filter chain with a 401 status code response | ||||||
| @@ -182,6 +173,12 @@ public class AuthenticationFilter implements ContainerRequestFilter { | |||||||
| 				.type(MediaType.APPLICATION_JSON).build()); | 				.type(MediaType.APPLICATION_JSON).build()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	private void abortWithForbidden(final ContainerRequestContext requestContext, final String message) { | ||||||
|  | 		final RestErrorResponse ret = new RestErrorResponse(Response.Status.FORBIDDEN, "FORBIDDEN", message); | ||||||
|  | 		LOGGER.error("Error UUID={}", ret.uuid); | ||||||
|  | 		requestContext.abortWith(Response.status(ret.status).header(HttpHeaders.WWW_AUTHENTICATE, message).entity(ret).type(MediaType.APPLICATION_JSON).build()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	protected UserByToken validateToken(final String authorization) throws Exception { | 	protected UserByToken validateToken(final String authorization) throws Exception { | ||||||
| 		LOGGER.info("Must be Override by the application implmentation, otherwise it dose not work"); | 		LOGGER.info("Must be Override by the application implmentation, otherwise it dose not work"); | ||||||
| 		return null; | 		return null; | ||||||
|   | |||||||
| @@ -15,8 +15,7 @@ public class CORSFilter implements ContainerResponseFilter { | |||||||
| 		// System.err.println("filter cors ..." + request.toString()); | 		// System.err.println("filter cors ..." + request.toString()); | ||||||
|  |  | ||||||
| 		response.getHeaders().add("Access-Control-Allow-Origin", "*"); | 		response.getHeaders().add("Access-Control-Allow-Origin", "*"); | ||||||
| 		response.getHeaders().add("Access-Control-Allow-Headers", "*"); | 		response.getHeaders().add("Access-Control-Allow-Headers", "Origin, content-type, Content-type, Accept, Authorization, mime-type, filename"); | ||||||
| 		// "Origin, content-type, Content-type, Accept, authorization, mime-type, filename"); |  | ||||||
| 		response.getHeaders().add("Access-Control-Allow-Credentials", "true"); | 		response.getHeaders().add("Access-Control-Allow-Credentials", "true"); | ||||||
| 		response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD"); | 		response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD"); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -35,13 +35,13 @@ class MySecurityContext implements SecurityContext { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public boolean isSecure() { | 	public boolean isSecure() { | ||||||
| 		return this.sheme.equalsIgnoreCase("https"); | 		return "https".equalsIgnoreCase(this.sheme); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public String getAuthenticationScheme() { | 	public String getAuthenticationScheme() { | ||||||
| 		if (this.contextPrincipale.userByToken != null) { | 		if (this.contextPrincipale.userByToken != null) { | ||||||
| 			return "Zota"; | 			return "Bearer"; | ||||||
| 		} | 		} | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -2,6 +2,9 @@ package org.kar.archidata.filter; | |||||||
|  |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  |  | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| import jakarta.ws.rs.container.ContainerRequestContext; | import jakarta.ws.rs.container.ContainerRequestContext; | ||||||
| import jakarta.ws.rs.container.ContainerRequestFilter; | import jakarta.ws.rs.container.ContainerRequestFilter; | ||||||
| import jakarta.ws.rs.container.PreMatching; | import jakarta.ws.rs.container.PreMatching; | ||||||
| @@ -11,8 +14,11 @@ import jakarta.ws.rs.ext.Provider; | |||||||
| @Provider | @Provider | ||||||
| @PreMatching | @PreMatching | ||||||
| public class OptionFilter implements ContainerRequestFilter { | public class OptionFilter implements ContainerRequestFilter { | ||||||
|  | 	private static final Logger LOGGER = LoggerFactory.getLogger(OptionFilter.class); | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void filter(final ContainerRequestContext requestContext) throws IOException { | 	public void filter(final ContainerRequestContext requestContext) throws IOException { | ||||||
|  | 		LOGGER.warn("Receive message from: [{}] {}", requestContext.getMethod(), requestContext.getUriInfo().getPath()); | ||||||
| 		if (requestContext.getMethod().contentEquals("OPTIONS")) { | 		if (requestContext.getMethod().contentEquals("OPTIONS")) { | ||||||
| 			requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build()); | 			requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build()); | ||||||
| 		} | 		} | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								src/org/kar/archidata/migration/AsyncCall.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/org/kar/archidata/migration/AsyncCall.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | package org.kar.archidata.migration; | ||||||
|  |  | ||||||
|  | public interface AsyncCall { | ||||||
|  | 	void doRequest() throws Exception; | ||||||
|  | } | ||||||
| @@ -13,13 +13,21 @@ import org.kar.archidata.tools.ConfigBaseVariable; | |||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| record Action(String action, List<String> filterDB) { | record Action(String action, AsyncCall async, List<String> filterDB) { | ||||||
| 	public Action(final String action) { | 	public Action(final String action) { | ||||||
| 		this(action, List.of()); | 		this(action, null, List.of()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public Action(final String action, final String filterDB) { | 	public Action(final String action, final String filterDB) { | ||||||
| 		this(action, List.of(filterDB)); | 		this(action, null, List.of(filterDB)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public Action(final AsyncCall async) { | ||||||
|  | 		this(null, async, List.of()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public Action(final AsyncCall async, final String filterDB) { | ||||||
|  | 		this(null, async, List.of(filterDB)); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -40,7 +48,11 @@ public class MigrationSqlStep implements MigrationInterface { | |||||||
| 		} | 		} | ||||||
| 		for (int iii = 0; iii < this.actions.size(); iii++) { | 		for (int iii = 0; iii < this.actions.size(); iii++) { | ||||||
| 			final Action action = this.actions.get(iii); | 			final Action action = this.actions.get(iii); | ||||||
|  | 			if (action.action() != null) { | ||||||
| 				LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action()); | 				LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action()); | ||||||
|  | 			} else { | ||||||
|  | 				LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\nAsync lambda", iii, this.actions.size(), action.filterDB()); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -63,8 +75,13 @@ public class MigrationSqlStep implements MigrationInterface { | |||||||
| 			LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size()); | 			LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size()); | ||||||
| 			final Action action = this.actions.get(iii); | 			final Action action = this.actions.get(iii); | ||||||
|  |  | ||||||
|  | 			if (action.action() != null) { | ||||||
| 				LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType()); | 				LOGGER.info("SQL request: ```{}``` on '{}' current={}", action.action(), action.filterDB(), ConfigBaseVariable.getDBType()); | ||||||
| 				log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n"); | 				log.append("SQL: " + action.action() + " on " + action.filterDB() + "\n"); | ||||||
|  | 			} else { | ||||||
|  | 				LOGGER.info("SQL request: <Lambda> on '{}' current={}", action.filterDB(), ConfigBaseVariable.getDBType()); | ||||||
|  | 				log.append("SQL: <Lambda> on " + action.filterDB() + "\n"); | ||||||
|  | 			} | ||||||
| 			boolean isValid = true; | 			boolean isValid = true; | ||||||
| 			if (action.filterDB() != null && action.filterDB().size() > 0) { | 			if (action.filterDB() != null && action.filterDB().size() > 0) { | ||||||
| 				isValid = false; | 				isValid = false; | ||||||
| @@ -80,7 +97,11 @@ public class MigrationSqlStep implements MigrationInterface { | |||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			try { | 			try { | ||||||
|  | 				if (action.action() != null) { | ||||||
| 					DataAccess.executeQuerry(action.action()); | 					DataAccess.executeQuerry(action.action()); | ||||||
|  | 				} else { | ||||||
|  | 					action.async().doRequest(); | ||||||
|  | 				} | ||||||
| 			} catch (SQLException | IOException ex) { | 			} catch (SQLException | IOException ex) { | ||||||
| 				ex.printStackTrace(); | 				ex.printStackTrace(); | ||||||
| 				LOGGER.info("SQL request ERROR: ", ex.getMessage()); | 				LOGGER.info("SQL request ERROR: ", ex.getMessage()); | ||||||
| @@ -123,10 +144,18 @@ public class MigrationSqlStep implements MigrationInterface { | |||||||
| 		this.actions.add(new Action(action)); | 		this.actions.add(new Action(action)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public void addAction(final AsyncCall async) { | ||||||
|  | 		this.actions.add(new Action(async)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public void addAction(final String action, final String filterdBType) { | 	public void addAction(final String action, final String filterdBType) { | ||||||
| 		this.actions.add(new Action(action, filterdBType)); | 		this.actions.add(new Action(action, filterdBType)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public void addAction(final AsyncCall async, final String filterdBType) { | ||||||
|  | 		this.actions.add(new Action(async, filterdBType)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public void addClass(final Class<?> clazz) throws Exception { | 	public void addClass(final Class<?> clazz) throws Exception { | ||||||
| 		final List<String> tmp = DataFactory.createTable(clazz); | 		final List<String> tmp = DataFactory.createTable(clazz); | ||||||
| 		for (final String elem : tmp) { | 		for (final String elem : tmp) { | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| package org.kar.archidata.migration.model; | package org.kar.archidata.migration.model; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.DataDefault; |  | ||||||
| import org.kar.archidata.annotation.DataIfNotExists; | import org.kar.archidata.annotation.DataIfNotExists; | ||||||
| import org.kar.archidata.annotation.DataNotRead; | import org.kar.archidata.annotation.DataNotRead; | ||||||
| import org.kar.archidata.model.GenericDataSoftDelete; | import org.kar.archidata.model.GenericDataSoftDelete; | ||||||
| @@ -10,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; | |||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import jakarta.persistence.Column; | import jakarta.persistence.Column; | ||||||
| import jakarta.persistence.Table; | import jakarta.persistence.Table; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
| // For logs only | // For logs only | ||||||
| //public static final String TABLE_NAME = "KAR_migration"; | //public static final String TABLE_NAME = "KAR_migration"; | ||||||
| @@ -24,11 +24,11 @@ public class Migration extends GenericDataSoftDelete { | |||||||
| 	@Column(length = 256) | 	@Column(length = 256) | ||||||
| 	public String name; | 	public String name; | ||||||
| 	@DataNotRead | 	@DataNotRead | ||||||
| 	@DataDefault("'2'") | 	@DefaultValue("'2'") | ||||||
| 	@Schema(description = "Version of the migration engine") | 	@Schema(description = "Version of the migration engine") | ||||||
| 	public Integer version; | 	public Integer version; | ||||||
| 	@Column(nullable = false) | 	@Column(nullable = false) | ||||||
| 	@DataDefault("'0'") | 	@DefaultValue("'0'") | ||||||
| 	@Schema(description = "if the migration is well terminated or not") | 	@Schema(description = "if the migration is well terminated or not") | ||||||
| 	public Boolean terminated = false; | 	public Boolean terminated = false; | ||||||
| 	@Schema(description = "index in the migration progression") | 	@Schema(description = "index in the migration progression") | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| package org.kar.archidata.migration.model; | package org.kar.archidata.migration.model; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.DataDefault; |  | ||||||
| import org.kar.archidata.annotation.DataIfNotExists; | import org.kar.archidata.annotation.DataIfNotExists; | ||||||
| import org.kar.archidata.model.GenericDataSoftDelete; | import org.kar.archidata.model.GenericDataSoftDelete; | ||||||
|  |  | ||||||
| @@ -9,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; | |||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import jakarta.persistence.Column; | import jakarta.persistence.Column; | ||||||
| import jakarta.persistence.Table; | import jakarta.persistence.Table; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
| // For logs only | // For logs only | ||||||
| //public static final String TABLE_NAME = "KAR_migration"; | //public static final String TABLE_NAME = "KAR_migration"; | ||||||
| @@ -22,7 +22,7 @@ public class Migration1 extends GenericDataSoftDelete { | |||||||
| 	@Column(length = 256) | 	@Column(length = 256) | ||||||
| 	public String name; | 	public String name; | ||||||
| 	@Column(nullable = false) | 	@Column(nullable = false) | ||||||
| 	@DataDefault("'0'") | 	@DefaultValue("'0'") | ||||||
| 	@Schema(description = "if the migration is well terminated or not") | 	@Schema(description = "if the migration is well terminated or not") | ||||||
| 	public Boolean terminated = false; | 	public Boolean terminated = false; | ||||||
| 	@Schema(description = "index in the migration progression") | 	@Schema(description = "index in the migration progression") | ||||||
|   | |||||||
| @@ -11,8 +11,7 @@ import jakarta.persistence.Table; | |||||||
| @Table(name = "data") | @Table(name = "data") | ||||||
| @DataIfNotExists | @DataIfNotExists | ||||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | @JsonInclude(JsonInclude.Include.NON_NULL) | ||||||
| public class Data extends GenericDataSoftDelete { | public class Data extends UUIDGenericDataSoftDelete { | ||||||
|  |  | ||||||
| 	@Column(length = 128, nullable = false) | 	@Column(length = 128, nullable = false) | ||||||
| 	@Schema(description = "Sha512 of the data") | 	@Schema(description = "Sha512 of the data") | ||||||
| 	public String sha512; | 	public String sha512; | ||||||
|   | |||||||
| @@ -1,38 +1,15 @@ | |||||||
| package org.kar.archidata.model; | package org.kar.archidata.model; | ||||||
|  |  | ||||||
| import java.util.Date; |  | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.CreationTimestamp; |  | ||||||
| import org.kar.archidata.annotation.DataNotRead; |  | ||||||
| import org.kar.archidata.annotation.UpdateTimestamp; |  | ||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import jakarta.persistence.Column; | import jakarta.persistence.Column; | ||||||
| import jakarta.persistence.GeneratedValue; | import jakarta.persistence.GeneratedValue; | ||||||
| import jakarta.persistence.GenerationType; | import jakarta.persistence.GenerationType; | ||||||
| import jakarta.persistence.Id; | import jakarta.persistence.Id; | ||||||
| import jakarta.persistence.Temporal; |  | ||||||
| import jakarta.persistence.TemporalType; |  | ||||||
| import jakarta.validation.constraints.NotNull; |  | ||||||
|  |  | ||||||
| public class GenericData { | public class GenericData extends GenericTiming { | ||||||
| 	@Id | 	@Id | ||||||
| 	@GeneratedValue(strategy = GenerationType.IDENTITY) | 	@GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
| 	@Column(nullable = false, unique = true) | 	@Column(nullable = false, unique = true) | ||||||
| 	@Schema(description = "Unique Id of the object", required = false, readOnly = true, example = "123456") | 	@Schema(description = "Unique Id of the object", required = false, readOnly = true, example = "123456") | ||||||
| 	public Long id = null; | 	public Long id = null; | ||||||
| 	@DataNotRead |  | ||||||
| 	@CreationTimestamp |  | ||||||
| 	@Column(nullable = false) |  | ||||||
| 	@Temporal(TemporalType.TIMESTAMP) |  | ||||||
| 	@NotNull |  | ||||||
| 	@Schema(description = "Create time of the object", required = false, example = "2000-01-23T01:23:45.678+01:00", readOnly = true) |  | ||||||
| 	public Date createdAt = null; |  | ||||||
| 	@DataNotRead |  | ||||||
| 	@UpdateTimestamp |  | ||||||
| 	@Column(nullable = false) |  | ||||||
| 	@Temporal(TemporalType.TIMESTAMP) |  | ||||||
| 	@NotNull |  | ||||||
| 	@Schema(description = "When update the object", required = false, example = "2000-01-23T00:23:45.678Z", readOnly = true) |  | ||||||
| 	public Date updatedAt = null; |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,17 +1,17 @@ | |||||||
| package org.kar.archidata.model; | package org.kar.archidata.model; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.DataDefault; |  | ||||||
| import org.kar.archidata.annotation.DataDeleted; | import org.kar.archidata.annotation.DataDeleted; | ||||||
| import org.kar.archidata.annotation.DataNotRead; | import org.kar.archidata.annotation.DataNotRead; | ||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import jakarta.persistence.Column; | import jakarta.persistence.Column; | ||||||
| import jakarta.validation.constraints.NotNull; | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
| public class GenericDataSoftDelete extends GenericData { | public class GenericDataSoftDelete extends GenericData { | ||||||
| 	@DataNotRead | 	@DataNotRead | ||||||
| 	@Column(nullable = false) | 	@Column(nullable = false) | ||||||
| 	@DataDefault("'0'") | 	@DefaultValue("'0'") | ||||||
| 	@DataDeleted | 	@DataDeleted | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	@Schema(description = "Deleted state", hidden = true, required = false, readOnly = true) | 	@Schema(description = "Deleted state", hidden = true, required = false, readOnly = true) | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								src/org/kar/archidata/model/GenericTiming.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/org/kar/archidata/model/GenericTiming.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | package org.kar.archidata.model; | ||||||
|  |  | ||||||
|  | import java.util.Date; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.annotation.CreationTimestamp; | ||||||
|  | import org.kar.archidata.annotation.DataNotRead; | ||||||
|  | import org.kar.archidata.annotation.UpdateTimestamp; | ||||||
|  |  | ||||||
|  | import com.fasterxml.jackson.annotation.JsonFormat; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  |  | ||||||
|  | public class GenericTiming { | ||||||
|  | 	@DataNotRead | ||||||
|  | 	@CreationTimestamp | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@NotNull | ||||||
|  | 	@Schema(description = "Create time of the object", required = false, example = "2000-01-23T01:23:45.678+01:00", readOnly = true) | ||||||
|  | 	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") | ||||||
|  | 	public Date createdAt = null; | ||||||
|  | 	@DataNotRead | ||||||
|  | 	@UpdateTimestamp | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@NotNull | ||||||
|  | 	@Schema(description = "When update the object", required = false, example = "2000-01-23T00:23:45.678Z", readOnly = true) | ||||||
|  | 	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") | ||||||
|  | 	// public Instant updatedAt = null; | ||||||
|  | 	public Date updatedAt = null; | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								src/org/kar/archidata/model/UUIDGenericData.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/org/kar/archidata/model/UUIDGenericData.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | package org.kar.archidata.model; | ||||||
|  |  | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.persistence.Id; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
|  | public class UUIDGenericData extends GenericTiming { | ||||||
|  | 	@Id | ||||||
|  | 	@DefaultValue("(UUID_TO_BIN(UUID(), TRUE))") | ||||||
|  | 	@Column(nullable = false, unique = true) | ||||||
|  | 	@Schema(description = "Unique UUID of the object", required = false, readOnly = true, example = "e6b33c1c-d24d-11ee-b616-02420a030102") | ||||||
|  | 	public UUID id = null; | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/org/kar/archidata/model/UUIDGenericDataSoftDelete.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/org/kar/archidata/model/UUIDGenericDataSoftDelete.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | package org.kar.archidata.model; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.annotation.DataDeleted; | ||||||
|  | import org.kar.archidata.annotation.DataNotRead; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.persistence.Column; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
|  | public class UUIDGenericDataSoftDelete extends UUIDGenericData { | ||||||
|  | 	@DataNotRead | ||||||
|  | 	@Column(nullable = false) | ||||||
|  | 	@DefaultValue("'0'") | ||||||
|  | 	@DataDeleted | ||||||
|  | 	@NotNull | ||||||
|  | 	@Schema(description = "Deleted state", hidden = true, required = false, readOnly = true) | ||||||
|  | 	public Boolean deleted = null; | ||||||
|  | } | ||||||
| @@ -17,7 +17,6 @@ CREATE TABLE `user` ( | |||||||
| import java.sql.Timestamp; | import java.sql.Timestamp; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import org.kar.archidata.annotation.DataDefault; |  | ||||||
| import org.kar.archidata.annotation.DataIfNotExists; | import org.kar.archidata.annotation.DataIfNotExists; | ||||||
|  |  | ||||||
| import com.fasterxml.jackson.annotation.JsonInclude; | import com.fasterxml.jackson.annotation.JsonInclude; | ||||||
| @@ -26,6 +25,7 @@ import jakarta.persistence.Column; | |||||||
| import jakarta.persistence.FetchType; | import jakarta.persistence.FetchType; | ||||||
| import jakarta.persistence.ManyToMany; | import jakarta.persistence.ManyToMany; | ||||||
| import jakarta.persistence.Table; | import jakarta.persistence.Table; | ||||||
|  | import jakarta.ws.rs.DefaultValue; | ||||||
|  |  | ||||||
| @Table(name = "user") | @Table(name = "user") | ||||||
| @DataIfNotExists | @DataIfNotExists | ||||||
| @@ -35,13 +35,13 @@ public class User extends GenericDataSoftDelete { | |||||||
| 	public String login = null; | 	public String login = null; | ||||||
|  |  | ||||||
| 	public Timestamp lastConnection = null; | 	public Timestamp lastConnection = null; | ||||||
| 	@DataDefault("'0'") | 	@DefaultValue("'0'") | ||||||
| 	@Column(nullable = false) | 	@Column(nullable = false) | ||||||
| 	public boolean admin = false; | 	public boolean admin = false; | ||||||
| 	@DataDefault("'0'") | 	@DefaultValue("'0'") | ||||||
| 	@Column(nullable = false) | 	@Column(nullable = false) | ||||||
| 	public boolean blocked = false; | 	public boolean blocked = false; | ||||||
| 	@DataDefault("'0'") | 	@DefaultValue("'0'") | ||||||
| 	@Column(nullable = false) | 	@Column(nullable = false) | ||||||
| 	public boolean removed = false; | 	public boolean removed = false; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,6 +14,9 @@ public class ConfigBaseVariable { | |||||||
| 	static public String ssoAdress; | 	static public String ssoAdress; | ||||||
| 	static public String ssoToken; | 	static public String ssoToken; | ||||||
| 	static public String testMode; | 	static public String testMode; | ||||||
|  | 	static public String eMailFrom; | ||||||
|  | 	static public String eMailLogin; | ||||||
|  | 	static public String eMailPassword; | ||||||
|  |  | ||||||
| 	// For test only | 	// For test only | ||||||
| 	public static void clearAllValue() { | 	public static void clearAllValue() { | ||||||
| @@ -30,6 +33,9 @@ public class ConfigBaseVariable { | |||||||
| 		ssoAdress = System.getenv("SSO_ADDRESS"); | 		ssoAdress = System.getenv("SSO_ADDRESS"); | ||||||
| 		ssoToken = System.getenv("SSO_TOKEN"); | 		ssoToken = System.getenv("SSO_TOKEN"); | ||||||
| 		testMode = System.getenv("TEST_MODE"); | 		testMode = System.getenv("TEST_MODE"); | ||||||
|  | 		eMailFrom = System.getenv("EMAIL_FROM"); | ||||||
|  | 		eMailLogin = System.getenv("EMAIL_LOGIN"); | ||||||
|  | 		eMailPassword = System.getenv("EMAIL_PASSWORD"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static { | 	static { | ||||||
| @@ -120,4 +126,15 @@ public class ConfigBaseVariable { | |||||||
| 		} | 		} | ||||||
| 		return Boolean.parseBoolean(testMode); | 		return Boolean.parseBoolean(testMode); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public record EMailConfig(String from, String login, String password) { | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	public static EMailConfig getEMailConfig() { | ||||||
|  | 		if (eMailFrom == null || eMailLogin == null || eMailPassword == null) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  | 		return new EMailConfig(eMailFrom, eMailLogin, eMailPassword); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,13 +12,16 @@ import java.security.MessageDigest; | |||||||
| import java.security.NoSuchAlgorithmException; | import java.security.NoSuchAlgorithmException; | ||||||
| import java.sql.SQLException; | import java.sql.SQLException; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| import org.glassfish.jersey.media.multipart.FormDataContentDisposition; | import org.glassfish.jersey.media.multipart.FormDataContentDisposition; | ||||||
|  | import org.kar.archidata.api.DataResource; | ||||||
| import org.kar.archidata.dataAccess.DataAccess; | import org.kar.archidata.dataAccess.DataAccess; | ||||||
| import org.kar.archidata.dataAccess.QueryAnd; | import org.kar.archidata.dataAccess.QueryAnd; | ||||||
| import org.kar.archidata.dataAccess.QueryCondition; | import org.kar.archidata.dataAccess.QueryCondition; | ||||||
| import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; | import org.kar.archidata.dataAccess.addOn.AddOnDataJson; | ||||||
| import org.kar.archidata.dataAccess.options.Condition; | import org.kar.archidata.dataAccess.options.Condition; | ||||||
|  | import org.kar.archidata.dataAccess.options.ReadAllColumn; | ||||||
| import org.kar.archidata.model.Data; | import org.kar.archidata.model.Data; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
| @@ -64,19 +67,9 @@ public class DataTools { | |||||||
| 		return filePath; | 		return filePath; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static String getFileData(final long tmpFolderId) { |  | ||||||
| 		final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; |  | ||||||
| 		try { |  | ||||||
| 			createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); |  | ||||||
| 		} catch (final IOException e) { |  | ||||||
| 			e.printStackTrace(); |  | ||||||
| 		} |  | ||||||
| 		return filePath; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static Data getWithSha512(final String sha512) { | 	public static Data getWithSha512(final String sha512) { | ||||||
| 		try { | 		try { | ||||||
| 			return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512))); | 			return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)), new ReadAllColumn()); | ||||||
| 		} catch (final Exception e) { | 		} catch (final Exception e) { | ||||||
| 			// TODO Auto-generated catch block | 			// TODO Auto-generated catch block | ||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| @@ -122,7 +115,7 @@ public class DataTools { | |||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final String mediaPath = getFileData(out.id); | 		final String mediaPath = DataResource.getFileData(out.id); | ||||||
| 		LOGGER.info("src = {}", tmpPath); | 		LOGGER.info("src = {}", tmpPath); | ||||||
| 		LOGGER.info("dst = {}", mediaPath); | 		LOGGER.info("dst = {}", mediaPath); | ||||||
| 		Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); | 		Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); | ||||||
| @@ -132,7 +125,7 @@ public class DataTools { | |||||||
| 		return out; | 		return out; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static void undelete(final Long id) { | 	public static void undelete(final UUID id) { | ||||||
| 		try { | 		try { | ||||||
| 			DataAccess.unsetDelete(Data.class, id); | 			DataAccess.unsetDelete(Data.class, id); | ||||||
| 		} catch (final Exception e) { | 		} catch (final Exception e) { | ||||||
| @@ -218,7 +211,8 @@ public class DataTools { | |||||||
| 		return data; | 		return data; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static <T> Response uploadCover(final Class<T> clazz, final Long id, String fileName, final InputStream fileInputStream, final FormDataContentDisposition fileMetaData) { | 	public static <CLASS_TYPE, ID_TYPE> Response uploadCover(final Class<CLASS_TYPE> clazz, final ID_TYPE id, String fileName, final InputStream fileInputStream, | ||||||
|  | 			final FormDataContentDisposition fileMetaData) { | ||||||
| 		try { | 		try { | ||||||
| 			// correct input string stream : | 			// correct input string stream : | ||||||
| 			fileName = multipartCorrection(fileName); | 			fileName = multipartCorrection(fileName); | ||||||
| @@ -229,7 +223,7 @@ public class DataTools { | |||||||
| 			LOGGER.info("    - file_name: ", fileName); | 			LOGGER.info("    - file_name: ", fileName); | ||||||
| 			LOGGER.info("    - fileInputStream: {}", fileInputStream); | 			LOGGER.info("    - fileInputStream: {}", fileInputStream); | ||||||
| 			LOGGER.info("    - fileMetaData: {}", fileMetaData); | 			LOGGER.info("    - fileMetaData: {}", fileMetaData); | ||||||
| 			final T media = DataAccess.get(clazz, id); | 			final CLASS_TYPE media = DataAccess.get(clazz, id); | ||||||
| 			if (media == null) { | 			if (media == null) { | ||||||
| 				return Response.notModified("Media Id does not exist or removed...").build(); | 				return Response.notModified("Media Id does not exist or removed...").build(); | ||||||
| 			} | 			} | ||||||
| @@ -259,7 +253,13 @@ public class DataTools { | |||||||
| 			} | 			} | ||||||
| 			// Fist step: retrieve all the Id of each parents:... | 			// Fist step: retrieve all the Id of each parents:... | ||||||
| 			LOGGER.info("Find typeNode"); | 			LOGGER.info("Find typeNode"); | ||||||
| 			AddOnManyToMany.addLink(clazz, id, "cover", data.id); | 			if (id instanceof final Long idLong) { | ||||||
|  | 				AddOnDataJson.addLink(clazz, idLong, "covers", data.id); | ||||||
|  | 			} else if (id instanceof final UUID idUUID) { | ||||||
|  | 				AddOnDataJson.addLink(clazz, idUUID, "covers", data.id); | ||||||
|  | 			} else { | ||||||
|  | 				throw new IOException("Fail to add Cover can not detect type..."); | ||||||
|  | 			} | ||||||
| 			return Response.ok(DataAccess.get(clazz, id)).build(); | 			return Response.ok(DataAccess.get(clazz, id)).build(); | ||||||
| 		} catch (final Exception ex) { | 		} catch (final Exception ex) { | ||||||
| 			System.out.println("Cat ann unexpected error ... "); | 			System.out.println("Cat ann unexpected error ... "); | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ import java.util.Map; | |||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  |  | ||||||
|  | import org.kar.archidata.filter.AuthenticationFilter; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| @@ -64,7 +65,7 @@ class TestSigner implements JWSSigner { | |||||||
| public class JWTWrapper { | public class JWTWrapper { | ||||||
| 	static final Logger LOGGER = LoggerFactory.getLogger(JWTWrapper.class); | 	static final Logger LOGGER = LoggerFactory.getLogger(JWTWrapper.class); | ||||||
|  |  | ||||||
| 	private static RSAKey rsaJWK = null;; | 	private static RSAKey rsaJWK = null; | ||||||
| 	private static RSAKey rsaPublicJWK = null; | 	private static RSAKey rsaPublicJWK = null; | ||||||
|  |  | ||||||
| 	public static class PublicKey { | 	public static class PublicKey { | ||||||
| @@ -89,7 +90,7 @@ public class JWTWrapper { | |||||||
| 		con.setRequestProperty("Accept", "application/json"); | 		con.setRequestProperty("Accept", "application/json"); | ||||||
| 		final String ssoToken = ConfigBaseVariable.ssoToken(); | 		final String ssoToken = ConfigBaseVariable.ssoToken(); | ||||||
| 		if (ssoToken != null) { | 		if (ssoToken != null) { | ||||||
| 			con.setRequestProperty("Authorization", "Zota " + ssoToken); | 			con.setRequestProperty(AuthenticationFilter.APIKEY, ssoToken); | ||||||
| 		} | 		} | ||||||
| 		final int responseCode = con.getResponseCode(); | 		final int responseCode = con.getResponseCode(); | ||||||
|  |  | ||||||
| @@ -244,9 +245,7 @@ public class JWTWrapper { | |||||||
| 			// LOGGER.debug("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'"); | 			// LOGGER.debug("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'"); | ||||||
| 			// LOGGER.debug("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'"); | 			// LOGGER.debug("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'"); | ||||||
| 			return signedJWT.getJWTClaimsSet(); | 			return signedJWT.getJWTClaimsSet(); | ||||||
| 		} catch (final JOSEException ex) { | 		} catch (final JOSEException | ParseException e) { | ||||||
| 			ex.printStackTrace(); |  | ||||||
| 		} catch (final ParseException e) { |  | ||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| 		} | 		} | ||||||
| 		return null; | 		return null; | ||||||
|   | |||||||
| @@ -40,14 +40,14 @@ public class RESTApi { | |||||||
| 		final HttpClient client = HttpClient.newHttpClient(); | 		final HttpClient client = HttpClient.newHttpClient(); | ||||||
| 		Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1).uri(URI.create(this.baseUrl + urlOffset)); | 		Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1).uri(URI.create(this.baseUrl + urlOffset)); | ||||||
| 		if (this.token != null) { | 		if (this.token != null) { | ||||||
| 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + this.token); | 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token); | ||||||
| 		} | 		} | ||||||
| 		final HttpRequest request = requestBuilding.GET().build(); | 		final HttpRequest request = requestBuilding.GET().build(); | ||||||
| 		final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); | 		final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||||
| 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | ||||||
| 			try { | 			try { | ||||||
| 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | ||||||
| 				throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage); | 				throw out; | ||||||
| 			} catch (final MismatchedInputException ex) { | 			} catch (final MismatchedInputException ex) { | ||||||
| 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | ||||||
| 			} | 			} | ||||||
| @@ -111,7 +111,7 @@ public class RESTApi { | |||||||
| 		LOGGER.trace("call {}: {}", model, URI.create(this.baseUrl + urlOffset)); | 		LOGGER.trace("call {}: {}", model, URI.create(this.baseUrl + urlOffset)); | ||||||
| 		LOGGER.trace("DATA: {}", body); | 		LOGGER.trace("DATA: {}", body); | ||||||
| 		if (this.token != null) { | 		if (this.token != null) { | ||||||
| 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + this.token); | 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token); | ||||||
| 		} | 		} | ||||||
| 		if (body == null) { | 		if (body == null) { | ||||||
| 			body = ""; | 			body = ""; | ||||||
| @@ -123,7 +123,7 @@ public class RESTApi { | |||||||
| 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | ||||||
| 			try { | 			try { | ||||||
| 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | ||||||
| 				throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage); | 				throw out; | ||||||
| 			} catch (final MismatchedInputException ex) { | 			} catch (final MismatchedInputException ex) { | ||||||
| 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | ||||||
| 			} catch (final JsonParseException ex) { | 			} catch (final JsonParseException ex) { | ||||||
| @@ -143,7 +143,7 @@ public class RESTApi { | |||||||
| 		String body = null; | 		String body = null; | ||||||
| 		Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1).uri(URI.create(this.baseUrl + urlOffset)); | 		Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1).uri(URI.create(this.baseUrl + urlOffset)); | ||||||
| 		if (this.token != null) { | 		if (this.token != null) { | ||||||
| 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + this.token); | 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token); | ||||||
| 		} | 		} | ||||||
| 		if (data == null) { | 		if (data == null) { | ||||||
| 			body = ""; | 			body = ""; | ||||||
| @@ -156,7 +156,7 @@ public class RESTApi { | |||||||
| 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | ||||||
| 			try { | 			try { | ||||||
| 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | ||||||
| 				throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage); | 				throw out; | ||||||
| 			} catch (final MismatchedInputException ex) { | 			} catch (final MismatchedInputException ex) { | ||||||
| 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | ||||||
| 			} | 			} | ||||||
| @@ -171,14 +171,14 @@ public class RESTApi { | |||||||
| 		final HttpClient client = HttpClient.newHttpClient(); | 		final HttpClient client = HttpClient.newHttpClient(); | ||||||
| 		Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1).uri(URI.create(this.baseUrl + urlOffset)); | 		Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1).uri(URI.create(this.baseUrl + urlOffset)); | ||||||
| 		if (this.token != null) { | 		if (this.token != null) { | ||||||
| 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + this.token); | 			requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token); | ||||||
| 		} | 		} | ||||||
| 		final HttpRequest request = requestBuilding.DELETE().build(); | 		final HttpRequest request = requestBuilding.DELETE().build(); | ||||||
| 		final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); | 		final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||||
| 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | 		if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { | ||||||
| 			try { | 			try { | ||||||
| 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | 				final RESTErrorResponseExeption out = this.mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); | ||||||
| 				throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage); | 				throw out; | ||||||
| 			} catch (final MismatchedInputException ex) { | 			} catch (final MismatchedInputException ex) { | ||||||
| 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | 				throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body()); | ||||||
| 			} | 			} | ||||||
|   | |||||||
							
								
								
									
										69
									
								
								src/org/kar/archidata/tools/UuidUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/org/kar/archidata/tools/UuidUtils.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | package org.kar.archidata.tools; | ||||||
|  |  | ||||||
|  | import java.math.BigInteger; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.time.Instant; | ||||||
|  | import java.time.LocalDate; | ||||||
|  | import java.time.ZoneOffset; | ||||||
|  | import java.time.temporal.ChronoUnit; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | public class UuidUtils { | ||||||
|  |  | ||||||
|  | 	public static UUID asUuid(final BigInteger bigInteger) { | ||||||
|  | 		final long mostSignificantBits = bigInteger.longValue(); | ||||||
|  | 		final long leastSignificantBits = bigInteger.shiftRight(64).longValue(); | ||||||
|  | 		return new UUID(mostSignificantBits, leastSignificantBits); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static UUID asUuid(final byte[] bytes) { | ||||||
|  | 		final ByteBuffer bb = ByteBuffer.wrap(bytes); | ||||||
|  | 		final long firstLong = bb.getLong(); | ||||||
|  | 		final long secondLong = bb.getLong(); | ||||||
|  | 		return new UUID(firstLong, secondLong); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static byte[] asBytes(final UUID uuid) { | ||||||
|  | 		final ByteBuffer bb = ByteBuffer.allocate(16); | ||||||
|  | 		bb.putLong(uuid.getMostSignificantBits()); | ||||||
|  | 		bb.putLong(uuid.getLeastSignificantBits()); | ||||||
|  | 		return bb.array(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private static class Generator { | ||||||
|  | 		private long base; | ||||||
|  | 		private final long offset; | ||||||
|  | 		private long previous; | ||||||
|  |  | ||||||
|  | 		public Generator() { | ||||||
|  | 			this.offset = System.currentTimeMillis(); | ||||||
|  | 			// The local method never generate new UUID in the past, then we use the creation function time to prevent 2038 error | ||||||
|  | 			final Instant startingUUID = LocalDate.of(2024, 03, 19).atStartOfDay(ZoneOffset.UTC).toInstant(); | ||||||
|  | 			this.base = startingUUID.until(Instant.now(), ChronoUnit.SECONDS); | ||||||
|  | 			final String serveurBaseUUID = System.getenv("UUID_SERVER_ID"); | ||||||
|  | 			if (serveurBaseUUID != null) { | ||||||
|  | 				long serverId = Long.valueOf(serveurBaseUUID); | ||||||
|  | 				serverId %= 0xFFFF; | ||||||
|  | 				this.base += (serverId << (64 - 16)); | ||||||
|  | 			} else { | ||||||
|  | 				this.base += (1L << (64 - 16)); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public synchronized UUID next() { | ||||||
|  | 			long tmp = System.currentTimeMillis(); | ||||||
|  | 			if (this.previous >= tmp) { | ||||||
|  | 				tmp = this.previous + 1; | ||||||
|  | 			} | ||||||
|  | 			this.previous = tmp; | ||||||
|  | 			tmp -= this.offset; | ||||||
|  | 			return new UUID(Long.reverseBytes(tmp), this.base); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private static Generator generator = new Generator(); | ||||||
|  |  | ||||||
|  | 	public static UUID nextUUID() { | ||||||
|  | 		return generator.next(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										373
									
								
								src/resources/rest-tools.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								src/resources/rest-tools.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | |||||||
|  | /** @file | ||||||
|  |  * @author Edouard DUPIN | ||||||
|  |  * @copyright 2024, Edouard DUPIN, all right reserved | ||||||
|  |  * @license MPL-2 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import { RestErrorResponse } from "./model" | ||||||
|  |  | ||||||
|  | export enum HTTPRequestModel { | ||||||
|  |     DELETE = 'DELETE', | ||||||
|  |     GET = 'GET', | ||||||
|  |     PATCH = 'PATCH', | ||||||
|  |     POST = 'POST', | ||||||
|  |     PUT = 'PUT', | ||||||
|  | } | ||||||
|  | export enum HTTPMimeType { | ||||||
|  |     ALL = '*/*', | ||||||
|  |     CSV = 'text/csv', | ||||||
|  |     IMAGE = 'image/*', | ||||||
|  |     IMAGE_JPEG = 'image/jpeg', | ||||||
|  |     IMAGE_PNG = 'image/png', | ||||||
|  |     JSON = 'application/json', | ||||||
|  |     MULTIPART = 'multipart/form-data', | ||||||
|  |     OCTET_STREAM = 'application/octet-stream', | ||||||
|  |     TEXT_PLAIN = 'text/plain', | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface RESTConfig { | ||||||
|  |     // base of the server: http(s)://my.server.org/plop/api/ | ||||||
|  |     server: string; | ||||||
|  |     // Token to access of the data. | ||||||
|  |     token?: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface RESTModel { | ||||||
|  |     // base of the local API request: "sheep/{id}". | ||||||
|  |     endPoint: string; | ||||||
|  |     // Type of the request. | ||||||
|  |     requestType?: HTTPRequestModel; | ||||||
|  |     // Input type requested. | ||||||
|  |     accept?: HTTPMimeType; | ||||||
|  |     // Content of the local data. | ||||||
|  |     contentType?: HTTPMimeType; | ||||||
|  |     // Mode of the TOKEN in URL or Header (?token:${tokenInUrl}) | ||||||
|  |     tokenInUrl?: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface ModelResponseHttp { | ||||||
|  |     status: number; | ||||||
|  |     data: any; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isArrayOf<TYPE>( | ||||||
|  |     data: any, | ||||||
|  |     typeChecker: (subData: any) => subData is TYPE, | ||||||
|  |     length?: number | ||||||
|  | ): data is TYPE[] { | ||||||
|  |     if (!Array.isArray(data)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (!data.every(typeChecker)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (length !== undefined && data.length != length) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function isNullOrUndefined(data: any): data is undefined | null { | ||||||
|  |     return data === undefined || data === null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // generic progression callback | ||||||
|  | export type ProgressCallback = (count: number, total: number) => void; | ||||||
|  |  | ||||||
|  | export interface RESTAbort { | ||||||
|  |     abort?: () => boolean | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Rest generic callback have a basic model to upload and download advancement. | ||||||
|  | export interface RESTCallbacks { | ||||||
|  |     progressUpload?: ProgressCallback, | ||||||
|  |     progressDownload?: ProgressCallback, | ||||||
|  |     abortHandle?: RESTAbort, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export interface RESTRequestType { | ||||||
|  |     restModel: RESTModel, | ||||||
|  |     restConfig: RESTConfig, | ||||||
|  |     data?: any, | ||||||
|  |     params?: object, | ||||||
|  |     queries?: object, | ||||||
|  |     callback?: RESTCallbacks, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | function removeTrailingSlashes(input: string): string { | ||||||
|  |     if (isNullOrUndefined(input)) { | ||||||
|  |         return "undefined"; | ||||||
|  |     } | ||||||
|  |     return input.replace(/\/+$/, ''); | ||||||
|  | } | ||||||
|  | function removeLeadingSlashes(input: string): string { | ||||||
|  |     if (isNullOrUndefined(input)) { | ||||||
|  |         return ""; | ||||||
|  |     } | ||||||
|  |     return input.replace(/^\/+/, ''); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function RESTUrl({ restModel, restConfig, params, queries }: RESTRequestType): string { | ||||||
|  |     // Create the URL PATH: | ||||||
|  |     let generateUrl = `${removeTrailingSlashes(restConfig.server)}/${removeLeadingSlashes(restModel.endPoint)}`; | ||||||
|  |     if (params !== undefined) { | ||||||
|  |         for (let key of Object.keys(params)) { | ||||||
|  |             generateUrl = generateUrl.replaceAll(`{${key}}`, `${params[key]}`); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (queries === undefined && (restConfig.token === undefined || restModel.tokenInUrl !== true)) { | ||||||
|  |         return generateUrl; | ||||||
|  |     } | ||||||
|  |     const searchParams = new URLSearchParams(); | ||||||
|  |     if (queries !== undefined) { | ||||||
|  |         for (let key of Object.keys(queries)) { | ||||||
|  |             const value = queries[key]; | ||||||
|  |             if (Array.isArray(value)) { | ||||||
|  |                 for (let iii = 0; iii < value.length; iii++) { | ||||||
|  |                     searchParams.append(`${key}`, `${value[iii]}`); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 searchParams.append(`${key}`, `${value}`); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (restConfig.token !== undefined && restModel.tokenInUrl === true) { | ||||||
|  |         searchParams.append('Authorization', `Bearer ${restConfig.token}`); | ||||||
|  |     } | ||||||
|  |     return generateUrl + "?" + searchParams.toString(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export function fetchProgress(generateUrl: string, { method, headers, body }: { | ||||||
|  |     method: HTTPRequestModel, | ||||||
|  |     headers: any, | ||||||
|  |     body: any, | ||||||
|  | }, { progressUpload, progressDownload, abortHandle }: RESTCallbacks): Promise<Response> { | ||||||
|  |     const xhr = { | ||||||
|  |         io: new XMLHttpRequest() | ||||||
|  |     } | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         // Stream the upload progress | ||||||
|  |         if (progressUpload) { | ||||||
|  |             xhr.io.upload.addEventListener("progress", (dataEvent) => { | ||||||
|  |                 if (dataEvent.lengthComputable) { | ||||||
|  |                     //console.log(`    ==> has a progress event: ${dataEvent.loaded} / ${dataEvent.total}`); | ||||||
|  |                     progressUpload(dataEvent.loaded, dataEvent.total); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         // Stream the download progress | ||||||
|  |         if (progressDownload) { | ||||||
|  |             xhr.io.addEventListener("progress", (dataEvent) => { | ||||||
|  |                 if (dataEvent.lengthComputable) { | ||||||
|  |                     //console.log(`    ==> download progress:: ${dataEvent.loaded} / ${dataEvent.total}`); | ||||||
|  |                     progressUpload(dataEvent.loaded, dataEvent.total); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         if (abortHandle) { | ||||||
|  |             abortHandle.abort = () => { | ||||||
|  |                 if (xhr.io) { | ||||||
|  |                     console.log(`Request abort on the XMLHttpRequest: ${generateUrl}`); | ||||||
|  |                     xhr.io.abort(); | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |                 console.log(`Request abort (FAIL) on the XMLHttpRequest: ${generateUrl}`); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // Check if we have an internal Fail: | ||||||
|  |         xhr.io.addEventListener('error', () => { | ||||||
|  |             xhr.io = undefined; | ||||||
|  |             reject(new TypeError('Failed to fetch')) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Capture the end of the stream | ||||||
|  |         xhr.io.addEventListener("loadend", () => { | ||||||
|  |             if (xhr.io.readyState !== XMLHttpRequest.DONE) { | ||||||
|  |                 //console.log(`    ==> READY state`); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if (xhr.io.status === 0) { | ||||||
|  |                 //the stream has been aborted | ||||||
|  |                 reject(new TypeError('Fetch has been aborted')); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             // Stream is ended, transform in a generic response: | ||||||
|  |             const response = new Response(xhr.io.response, { | ||||||
|  |                 status: xhr.io.status, | ||||||
|  |                 statusText: xhr.io.statusText | ||||||
|  |             }); | ||||||
|  |             const headersArray = xhr.io.getAllResponseHeaders().trim().replaceAll("\r\n", "\n").split('\n'); | ||||||
|  |             headersArray.forEach(function (header) { | ||||||
|  |                 const firstColonIndex = header.indexOf(':'); | ||||||
|  |                 if (firstColonIndex !== -1) { | ||||||
|  |                     var key = header.substring(0, firstColonIndex).trim(); | ||||||
|  |                     var value = header.substring(firstColonIndex + 1).trim(); | ||||||
|  |                     response.headers.set(key, value); | ||||||
|  |                 } else { | ||||||
|  |                     response.headers.set(header, ""); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |             xhr.io = undefined; | ||||||
|  |             resolve(response); | ||||||
|  |         }); | ||||||
|  |         xhr.io.open(method, generateUrl, true); | ||||||
|  |         if (!isNullOrUndefined(headers)) { | ||||||
|  |             for (const [key, value] of Object.entries(headers)) { | ||||||
|  |                 xhr.io.setRequestHeader(key, value as string); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         xhr.io.send(body); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function RESTRequest({ restModel, restConfig, data, params, queries, callback }: RESTRequestType): Promise<ModelResponseHttp> { | ||||||
|  |     // Create the URL PATH: | ||||||
|  |     let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries }); | ||||||
|  |     let headers: any = {}; | ||||||
|  |     if (restConfig.token !== undefined && restModel.tokenInUrl !== true) { | ||||||
|  |         headers['Authorization'] = `Bearer ${restConfig.token}`; | ||||||
|  |     } | ||||||
|  |     if (restModel.accept !== undefined) { | ||||||
|  |         headers['Accept'] = restModel.accept; | ||||||
|  |     } | ||||||
|  |     if (restModel.requestType !== HTTPRequestModel.GET) { | ||||||
|  |         // if Get we have not a content type, the body is empty | ||||||
|  |         if (restModel.contentType !== HTTPMimeType.MULTIPART) { | ||||||
|  |             // special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****" | ||||||
|  |             headers['Content-Type'] = restModel.contentType; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     let body = data; | ||||||
|  |     if (restModel.contentType === HTTPMimeType.JSON) { | ||||||
|  |         body = JSON.stringify(data); | ||||||
|  |     } else if (restModel.contentType === HTTPMimeType.MULTIPART) { | ||||||
|  |         const formData = new FormData(); | ||||||
|  |         for (const name in data) { | ||||||
|  |             formData.append(name, data[name]); | ||||||
|  |         } | ||||||
|  |         body = formData | ||||||
|  |     } | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         let action: undefined | Promise<Response> = undefined; | ||||||
|  |         if (isNullOrUndefined(callback) | ||||||
|  |             || (isNullOrUndefined(callback.progressDownload) | ||||||
|  |                 && isNullOrUndefined(callback.progressUpload) | ||||||
|  |                 && isNullOrUndefined(callback.abortHandle))) { | ||||||
|  |             // No information needed: call the generic fetch interface | ||||||
|  |             action = fetch(generateUrl, { | ||||||
|  |                 method: restModel.requestType, | ||||||
|  |                 headers, | ||||||
|  |                 body, | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             // need progression information: call old fetch model (XMLHttpRequest) that permit to keep % upload and % download for HTTP1.x | ||||||
|  |             action = fetchProgress(generateUrl, { | ||||||
|  |                 method: restModel.requestType ?? HTTPRequestModel.GET, | ||||||
|  |                 headers, | ||||||
|  |                 body, | ||||||
|  |             }, callback); | ||||||
|  |         } | ||||||
|  |         action.then((response: Response) => { | ||||||
|  |             if (response.status >= 200 && response.status <= 299) { | ||||||
|  |                 const contentType = response.headers.get('Content-Type'); | ||||||
|  |                 if (restModel.accept !== contentType) { | ||||||
|  |                     reject({ | ||||||
|  |                         time: Date().toString(), | ||||||
|  |                         status: 901, | ||||||
|  |                         error: `REST check wrong type: ${restModel.accept} != ${contentType}`, | ||||||
|  |                         statusMessage: "Fetch error", | ||||||
|  |                         message: "rest-tools.ts Wrong type in the message return type" | ||||||
|  |                     } as RestErrorResponse); | ||||||
|  |                 } else if (contentType === HTTPMimeType.JSON) { | ||||||
|  |                     response | ||||||
|  |                         .json() | ||||||
|  |                         .then((value: any) => { | ||||||
|  |                             //console.log(`RECEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`); | ||||||
|  |                             resolve({ status: response.status, data: value }); | ||||||
|  |                         }) | ||||||
|  |                         .catch((reason: any) => { | ||||||
|  |                             reject({ | ||||||
|  |                                 time: Date().toString(), | ||||||
|  |                                 status: 902, | ||||||
|  |                                 error: `REST parse json fail: ${reason}`, | ||||||
|  |                                 statusMessage: "Fetch parse error", | ||||||
|  |                                 message: "rest-tools.ts Wrong message model to parse" | ||||||
|  |                             } as RestErrorResponse); | ||||||
|  |                         }); | ||||||
|  |                 } else { | ||||||
|  |                     resolve({ status: response.status, data: response.body }); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 reject({ | ||||||
|  |                     time: Date().toString(), | ||||||
|  |                     status: response.status, | ||||||
|  |                     error: `${response.body}`, | ||||||
|  |                     statusMessage: "Fetch code error", | ||||||
|  |                     message: "rest-tools.ts Wrong return code" | ||||||
|  |                 } as RestErrorResponse); | ||||||
|  |             } | ||||||
|  |         }).catch((error: any) => { | ||||||
|  |             reject({ | ||||||
|  |                 time: Date(), | ||||||
|  |                 status: 999, | ||||||
|  |                 error: error, | ||||||
|  |                 statusMessage: "Fetch catch error", | ||||||
|  |                 message: "rest-tools.ts detect an error in the fetch request" | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export function RESTRequestJson<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE> { | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         RESTRequest(request).then((value: ModelResponseHttp) => { | ||||||
|  |             if (checker(value.data)) { | ||||||
|  |                 resolve(value.data); | ||||||
|  |             } else { | ||||||
|  |                 reject({ | ||||||
|  |                     time: Date().toString(), | ||||||
|  |                     status: 950, | ||||||
|  |                     error: "REST Fail to verify the data", | ||||||
|  |                     statusMessage: "API cast ERROR", | ||||||
|  |                     message: "api.ts Check type as fail" | ||||||
|  |                 } as RestErrorResponse); | ||||||
|  |             } | ||||||
|  |         }).catch((reason: RestErrorResponse) => { | ||||||
|  |             reject(reason); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | export function RESTRequestJsonArray<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE[]> { | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         RESTRequest(request).then((value: ModelResponseHttp) => { | ||||||
|  |             if (isArrayOf(value.data, checker)) { | ||||||
|  |                 resolve(value.data); | ||||||
|  |             } else { | ||||||
|  |                 reject({ | ||||||
|  |                     time: Date().toString(), | ||||||
|  |                     status: 950, | ||||||
|  |                     error: "REST Fail to verify the data", | ||||||
|  |                     statusMessage: "API cast ERROR", | ||||||
|  |                     message: "api.ts Check type as fail" | ||||||
|  |                 } as RestErrorResponse); | ||||||
|  |             } | ||||||
|  |         }).catch((reason: RestErrorResponse) => { | ||||||
|  |             reject(reason); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function RESTRequestVoid(request: RESTRequestType): Promise<void> { | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         RESTRequest(request).then((value: ModelResponseHttp) => { | ||||||
|  |             resolve(); | ||||||
|  |         }).catch((reason: RestErrorResponse) => { | ||||||
|  |             reject(reason); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | } | ||||||
| @@ -53,7 +53,7 @@ public class TestJson { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(SerializeAsJson.class); | 		final List<String> sqlCommand = DataFactory.createTable(SerializeAsJson.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,7 +53,7 @@ public class TestListJson { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJson.class); | 		final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJson.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -57,7 +57,7 @@ public class TestManyToMany { | |||||||
| 		sqlCommand.addAll(sqlCommand2); | 		sqlCommand.addAll(sqlCommand2); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -56,7 +56,7 @@ public class TestManyToOne { | |||||||
| 		sqlCommand.addAll(sqlCommand2); | 		sqlCommand.addAll(sqlCommand2); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -51,7 +51,7 @@ public class TestOneToMany { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(TypesTable.class); | 		final List<String> sqlCommand = DataFactory.createTable(TypesTable.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										121
									
								
								test/src/test/kar/archidata/TestRawQuery.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								test/src/test/kar/archidata/TestRawQuery.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | package test.kar.archidata; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import org.junit.jupiter.api.AfterAll; | ||||||
|  | import org.junit.jupiter.api.Assertions; | ||||||
|  | import org.junit.jupiter.api.BeforeAll; | ||||||
|  | import org.junit.jupiter.api.MethodOrderer; | ||||||
|  | import org.junit.jupiter.api.Order; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import org.junit.jupiter.api.TestMethodOrder; | ||||||
|  | import org.junit.jupiter.api.extension.ExtendWith; | ||||||
|  | import org.kar.archidata.GlobalConfiguration; | ||||||
|  | import org.kar.archidata.dataAccess.DataAccess; | ||||||
|  | import org.kar.archidata.dataAccess.DataFactory; | ||||||
|  | import org.kar.archidata.db.DBEntry; | ||||||
|  | import org.kar.archidata.tools.ConfigBaseVariable; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import test.kar.archidata.model.TypesTable; | ||||||
|  |  | ||||||
|  | @ExtendWith(StepwiseExtension.class) | ||||||
|  | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) | ||||||
|  | public class TestRawQuery { | ||||||
|  | 	final static private Logger LOGGER = LoggerFactory.getLogger(TestTypes.class); | ||||||
|  |  | ||||||
|  | 	@BeforeAll | ||||||
|  | 	public static void configureWebServer() throws Exception { | ||||||
|  | 		if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) { | ||||||
|  | 			ConfigBaseVariable.dbType = "sqlite"; | ||||||
|  | 			ConfigBaseVariable.dbHost = "memory"; | ||||||
|  | 			// for test we need to connect all time the DB | ||||||
|  | 			ConfigBaseVariable.dbKeepConnected = "true"; | ||||||
|  | 		} | ||||||
|  | 		// Connect the dataBase... | ||||||
|  | 		final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); | ||||||
|  | 		entry.connect(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@AfterAll | ||||||
|  | 	public static void removeDataBase() throws IOException { | ||||||
|  | 		LOGGER.info("Remove the test db"); | ||||||
|  | 		DBEntry.closeAllForceMode(); | ||||||
|  | 		ConfigBaseVariable.clearAllValue(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Order(1) | ||||||
|  | 	@Test | ||||||
|  | 	public void testCreateTable() throws Exception { | ||||||
|  | 		final List<String> sqlCommand = DataFactory.createTable(TypesTable.class); | ||||||
|  | 		for (final String elem : sqlCommand) { | ||||||
|  | 			LOGGER.debug("request: '{}'", elem); | ||||||
|  | 			DataAccess.executeSimpleQuerry(elem); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Order(2) | ||||||
|  | 	@Test | ||||||
|  | 	public void testGet() throws Exception { | ||||||
|  |  | ||||||
|  | 		final TypesTable test = new TypesTable(); | ||||||
|  | 		test.intData = 95; | ||||||
|  | 		test.floatData = 1.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		test.intData = 96; | ||||||
|  | 		test.floatData = 2.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		test.intData = 97; | ||||||
|  | 		test.floatData = 3.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		test.intData = 98; | ||||||
|  | 		test.floatData = 4.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		test.intData = 99; | ||||||
|  | 		test.floatData = 5.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		test.intData = 99; | ||||||
|  | 		test.floatData = 6.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		test.intData = 99; | ||||||
|  | 		test.floatData = 7.0F; | ||||||
|  | 		DataAccess.insert(test); | ||||||
|  | 		{ | ||||||
|  | 			String querry = """ | ||||||
|  | 					SELECT * | ||||||
|  | 					FROM TypesTable | ||||||
|  | 					WHERE `intData` = ? | ||||||
|  | 					ORDER BY id DESC | ||||||
|  | 					"""; | ||||||
|  | 			List<Object> parameters = List.of(Integer.valueOf(99)); | ||||||
|  | 			// Try to retrieve all the data: | ||||||
|  | 			final List<TypesTable> retrieve = DataAccess.query(TypesTable.class, querry, parameters); | ||||||
|  |  | ||||||
|  | 			Assertions.assertNotNull(retrieve); | ||||||
|  | 			Assertions.assertEquals(3, retrieve.size()); | ||||||
|  | 			Assertions.assertEquals(99, retrieve.get(0).intData); | ||||||
|  | 			Assertions.assertEquals(7.0F, retrieve.get(0).floatData); | ||||||
|  | 			Assertions.assertEquals(6.0F, retrieve.get(1).floatData); | ||||||
|  | 			Assertions.assertEquals(5.0F, retrieve.get(2).floatData); | ||||||
|  | 		} | ||||||
|  | 		{ | ||||||
|  |  | ||||||
|  | 			String querry = """ | ||||||
|  | 					SELECT DISTINCT intData | ||||||
|  | 					FROM TypesTable | ||||||
|  | 					WHERE `intData` = ? | ||||||
|  | 					ORDER BY id DESC | ||||||
|  | 					"""; | ||||||
|  | 			List<Object> parameters = List.of(Integer.valueOf(99)); | ||||||
|  | 			// Try to retrieve all the data: | ||||||
|  | 			final List<TypesTable> retrieve = DataAccess.query(TypesTable.class, querry, parameters); | ||||||
|  |  | ||||||
|  | 			Assertions.assertNotNull(retrieve); | ||||||
|  | 			Assertions.assertEquals(1, retrieve.size()); | ||||||
|  | 			Assertions.assertEquals(99, retrieve.get(0).intData); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -65,7 +65,7 @@ public class TestSimpleTable { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(SimpleTable.class); | 		final List<String> sqlCommand = DataFactory.createTable(SimpleTable.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 		final SimpleTable test = new SimpleTable(); | 		final SimpleTable test = new SimpleTable(); | ||||||
| 		test.data = TestSimpleTable.DATA_INJECTED; | 		test.data = TestSimpleTable.DATA_INJECTED; | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ public class TestSimpleTableSoftDelete { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(SimpleTableSoftDelete.class); | 		final List<String> sqlCommand = DataFactory.createTable(SimpleTableSoftDelete.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 		final SimpleTableSoftDelete test = new SimpleTableSoftDelete(); | 		final SimpleTableSoftDelete test = new SimpleTableSoftDelete(); | ||||||
| 		test.data = TestSimpleTableSoftDelete.DATA_INJECTED; | 		test.data = TestSimpleTableSoftDelete.DATA_INJECTED; | ||||||
|   | |||||||
| @@ -53,7 +53,7 @@ public class TestTypeEnum1 { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(TypesEnum1.class); | 		final List<String> sqlCommand = DataFactory.createTable(TypesEnum1.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,7 +53,7 @@ public class TestTypeEnum2 { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(TypesEnum2.class); | 		final List<String> sqlCommand = DataFactory.createTable(TypesEnum2.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -57,7 +57,7 @@ public class TestTypes { | |||||||
| 		final List<String> sqlCommand = DataFactory.createTable(TypesTable.class); | 		final List<String> sqlCommand = DataFactory.createTable(TypesTable.class); | ||||||
| 		for (final String elem : sqlCommand) { | 		for (final String elem : sqlCommand) { | ||||||
| 			LOGGER.debug("request: '{}'", elem); | 			LOGGER.debug("request: '{}'", elem); | ||||||
| 			DataAccess.executeSimpleQuerry(elem, false); | 			DataAccess.executeSimpleQuerry(elem); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,5 +23,5 @@ function __run() #(step, name, cmd) | |||||||
|     fi |     fi | ||||||
| } | } | ||||||
|  |  | ||||||
| __run "1/1" "Check JAVA code format" "mvn formatter:verify" | __run "1/1" "Check JAVA code format" "mvn formatter:validate" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| 0.6.0 | 0.7.3 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user