Compare commits
	
		
			19 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 875b4b313b | |||
| 15a7814a3b | |||
| 530d254bf2 | |||
| e1d9da70c8 | |||
| c13f910620 | |||
| 6944331761 | |||
| 151aa498e5 | |||
| db6a20fa02 | |||
| 8e913b54ad | |||
| 092bef5a7b | |||
| e5d75bc97b | |||
| 7c217716c9 | |||
| 526f902eae | |||
| 42ac2f3056 | |||
| 389e4138c3 | |||
| 6584022861 | |||
| 41fb181545 | |||
| 56609e4f59 | |||
| e0b7ed1e1e | 
| @@ -37,8 +37,8 @@ | |||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations"> | 	<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="optional" value="true"/> |  | ||||||
| 			<attribute name="test" value="true"/> | 			<attribute name="test" value="true"/> | ||||||
|  | 			<attribute name="optional" value="true"/> | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="output" path="target/classes"/> | 	<classpathentry kind="output" path="target/classes"/> | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								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.3</version> | 	<version>0.7.0</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> | ||||||
| @@ -114,6 +114,12 @@ | |||||||
| 			<artifactId>jackson-dataformat-csv</artifactId> | 			<artifactId>jackson-dataformat-csv</artifactId> | ||||||
| 			<version>2.16.1</version> | 			<version>2.16.1</version> | ||||||
| 		</dependency> | 		</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> | ||||||
| @@ -179,6 +185,11 @@ | |||||||
|  |  | ||||||
| 	<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> | ||||||
|   | |||||||
| @@ -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 { | ||||||
|   | |||||||
| @@ -5,10 +5,9 @@ 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 AsyncType { | ||||||
| 
 | 	Class<?> value(); | ||||||
| 	String 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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
| @@ -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); | ||||||
| @@ -92,6 +93,24 @@ 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); | ||||||
| @@ -137,7 +156,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 +167,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 +244,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 +259,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 +273,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 +281,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 +301,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(); | ||||||
| @@ -325,17 +360,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 (with a beautifull name (permit download with basic name)", tags = "SYSTEM") | 	@Operation(description = "Get back some data from the data environment (with a beautifull 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(); | ||||||
|   | |||||||
| @@ -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(); | ||||||
|   | |||||||
| @@ -10,15 +10,16 @@ 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.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; | ||||||
| @@ -34,12 +35,14 @@ 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: | ||||||
| @@ -191,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); | ||||||
| @@ -251,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) { | ||||||
| @@ -288,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); | ||||||
| @@ -397,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()) { | ||||||
| @@ -449,6 +487,20 @@ public class DataAccess { | |||||||
| 	// TODO: this function will replace the previous one !!! | 	// TODO: this function will replace the previous one !!! | ||||||
| 	protected static RetreiveFromDB createSetValueFromDbCallback(final int count, final Field field) throws Exception { | 	protected static RetreiveFromDB createSetValueFromDbCallback(final int count, final Field field) throws Exception { | ||||||
| 		final Class<?> type = field.getType(); | 		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) { | 		if (type == Long.class) { | ||||||
| 			return (final ResultSet rs, final Object obj) -> { | 			return (final ResultSet rs, final Object obj) -> { | ||||||
| 				final Long tmp = rs.getLong(count); | 				final Long tmp = rs.getLong(count); | ||||||
| @@ -581,6 +633,16 @@ public class DataAccess { | |||||||
| 				} | 				} | ||||||
| 			}; | 			}; | ||||||
| 		} | 		} | ||||||
|  | 		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) { | 		if (type == LocalDate.class) { | ||||||
| 			return (final ResultSet rs, final Object obj) -> { | 			return (final ResultSet rs, final Object obj) -> { | ||||||
| 				final java.sql.Date tmp = rs.getDate(count); | 				final java.sql.Date tmp = rs.getDate(count); | ||||||
| @@ -672,7 +734,10 @@ public class DataAccess { | |||||||
| 		final DBEntry entry = DBInterfaceOption.getAutoEntry(options); | 		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; | ||||||
| @@ -683,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())) { | ||||||
| @@ -708,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; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @@ -741,15 +830,21 @@ 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(); | ||||||
|  | 				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); | ||||||
| @@ -772,7 +867,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; | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| @@ -786,9 +881,28 @@ 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)."); | ||||||
| 					} | 					} | ||||||
| @@ -797,11 +911,14 @@ 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 !!!"); | ||||||
| 				} | 				} | ||||||
| @@ -899,13 +1016,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"); | ||||||
| @@ -957,7 +1082,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; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @@ -1004,7 +1129,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; | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| @@ -1026,7 +1151,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) { | ||||||
| @@ -1160,6 +1288,10 @@ public class DataAccess { | |||||||
| 			querySelect.append(query.toString()); | 			querySelect.append(query.toString()); | ||||||
| 			query = querySelect; | 			query = querySelect; | ||||||
| 			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) { | ||||||
| 				orders.generateQuerry(query, tableName); | 				orders.generateQuerry(query, tableName); | ||||||
| @@ -1508,7 +1640,14 @@ public class DataAccess { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* - useful code to manage external query: List<T> query<T>(class<T> clazz, ); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2"); */ | 	/** 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 { | 	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); | 		final QueryOptions options = new QueryOptions(option); | ||||||
| 		return query(clazz, query, parameters, options); | 		return query(clazz, query, parameters, options); | ||||||
| @@ -1529,6 +1668,19 @@ public class DataAccess { | |||||||
| 		try { | 		try { | ||||||
| 			final CountInOut count = new CountInOut(); | 			final CountInOut count = new CountInOut(); | ||||||
| 			condition.whereAppendQuery(query, null, options, null); | 			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()); | 			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); | ||||||
| @@ -1540,16 +1692,21 @@ public class DataAccess { | |||||||
| 				iii.inc(); | 				iii.inc(); | ||||||
| 			} | 			} | ||||||
| 			condition.injectQuerry(ps, iii); | 			condition.injectQuerry(ps, iii); | ||||||
|  | 			if (limit != null) { | ||||||
|  | 				limit.injectQuerry(ps, iii); | ||||||
|  | 			} | ||||||
| 			// execute the request | 			// execute the request | ||||||
| 			final ResultSet rs = ps.executeQuery(); | 			final ResultSet rs = ps.executeQuery(); | ||||||
| 			final ResultSetMetaData rsmd = rs.getMetaData(); | 			final ResultSetMetaData rsmd = rs.getMetaData(); | ||||||
| 			final List<RetreiveFromDB> actionToRetreive = new ArrayList<>(); | 			final List<RetreiveFromDB> actionToRetreive = new ArrayList<>(); | ||||||
|  | 			LOGGER.info("Field:"); | ||||||
| 			for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) { | 			for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) { | ||||||
| 				final String name = rsmd.getColumnName(jjj + 1); | 				final String label = rsmd.getColumnLabel(jjj + 1); | ||||||
|  | 				LOGGER.info("    - {}:{}", jjj, label); | ||||||
| 				// find field name ... | 				// find field name ... | ||||||
| 				final Field field = AnnotationTools.getFieldNamed(clazz, name); | 				final Field field = AnnotationTools.getFieldNamed(clazz, label); | ||||||
| 				if (field == null) { | 				if (field == null) { | ||||||
| 					throw new DataAccessException("Querry with unknown field: '" + name + "'"); | 					throw new DataAccessException("Querry with unknown field: '" + label + "'"); | ||||||
| 				} | 				} | ||||||
| 				// create the callback... | 				// create the callback... | ||||||
| 				final RetreiveFromDB element = createSetValueFromDbCallback(jjj + 1, field); | 				final RetreiveFromDB element = createSetValueFromDbCallback(jjj + 1, field); | ||||||
| @@ -1558,7 +1715,6 @@ public class DataAccess { | |||||||
|  |  | ||||||
| 			while (rs.next()) { | 			while (rs.next()) { | ||||||
| 				count.value = 1; | 				count.value = 1; | ||||||
| 				final CountInOut countNotNull = new CountInOut(0); |  | ||||||
| 				Object data = null; | 				Object data = null; | ||||||
| 				for (final Constructor<?> contructor : clazz.getConstructors()) { | 				for (final Constructor<?> contructor : clazz.getConstructors()) { | ||||||
| 					if (contructor.getParameterCount() == 0) { | 					if (contructor.getParameterCount() == 0) { | ||||||
| @@ -1590,5 +1746,4 @@ public class DataAccess { | |||||||
| 		} | 		} | ||||||
| 		return outs; | 		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 "); | ||||||
|   | |||||||
							
								
								
									
										572
									
								
								src/org/kar/archidata/dataAccess/DataFactoryTsApi.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										572
									
								
								src/org/kar/archidata/dataAccess/DataFactoryTsApi.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,572 @@ | |||||||
|  | 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.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, 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 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); | ||||||
|  | 			} | ||||||
|  | 			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,"); | ||||||
|  | 			} | ||||||
|  | 			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(","); | ||||||
|  | 			} | ||||||
|  | 			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,"); | ||||||
|  | 			} | ||||||
|  | 			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; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										436
									
								
								src/org/kar/archidata/dataAccess/DataFactoryZod.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								src/org/kar/archidata/dataAccess/DataFactoryZod.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,436 @@ | |||||||
|  | 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("'"); | ||||||
|  | 			} | ||||||
|  | 			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("'"); | ||||||
|  | 			} | ||||||
|  | 			out.append("}"); | ||||||
|  | 		} | ||||||
|  | 		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 { | ||||||
|   | |||||||
| @@ -5,15 +5,23 @@ 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; | ||||||
|  |  | ||||||
| @@ -88,8 +96,8 @@ public class AddOnDataJson implements DataAccessAddOn { | |||||||
| 		if (!rs.wasNull()) { | 		if (!rs.wasNull()) { | ||||||
| 			final ObjectMapper objectMapper = new ObjectMapper(); | 			final ObjectMapper objectMapper = new ObjectMapper(); | ||||||
| 			if (field.getType() == List.class) { | 			if (field.getType() == List.class) { | ||||||
| 				ParameterizedType listType = (ParameterizedType) field.getGenericType(); | 				final ParameterizedType listType = (ParameterizedType) field.getGenericType(); | ||||||
| 				Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0]; | 				final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0]; | ||||||
| 				if (listClass == Long.class) { | 				if (listClass == Long.class) { | ||||||
| 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType()); | 					final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType()); | ||||||
| 					field.set(data, dataParsed); | 					field.set(data, dataParsed); | ||||||
| @@ -120,6 +128,12 @@ public class AddOnDataJson implements DataAccessAddOn { | |||||||
| 					field.set(data, dataParsed); | 					field.set(data, dataParsed); | ||||||
| 					return; | 					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); | ||||||
| @@ -131,4 +145,143 @@ 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)); | ||||||
|  |  | ||||||
|  | 	}*/ | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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"); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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"); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,49 +0,0 @@ | |||||||
| package org.kar.archidata.serializer; |  | ||||||
|  |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.OutputStream; |  | ||||||
| import java.lang.annotation.Annotation; |  | ||||||
| import java.lang.reflect.Type; |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| import com.fasterxml.jackson.dataformat.csv.CsvMapper; |  | ||||||
| import com.fasterxml.jackson.dataformat.csv.CsvSchema; |  | ||||||
|  |  | ||||||
| import jakarta.ws.rs.Produces; |  | ||||||
| import jakarta.ws.rs.WebApplicationException; |  | ||||||
| import jakarta.ws.rs.core.MediaType; |  | ||||||
| import jakarta.ws.rs.core.MultivaluedMap; |  | ||||||
| import jakarta.ws.rs.ext.MessageBodyWriter; |  | ||||||
| import jakarta.ws.rs.ext.Provider; |  | ||||||
|  |  | ||||||
| /** Body writer use in jersey with : In your main: ```java rc.register(new CSVMessageBodyWritter()); ``` |  | ||||||
|  * |  | ||||||
|  * and in the produce element: ```java |  | ||||||
|  * @GET |  | ||||||
|  * @Produces(CSVMessageBodyWritter.CSV_TYPE) public List<Data> getData() {} ``` */ |  | ||||||
| @Provider |  | ||||||
| @Produces("text/csv") |  | ||||||
| public class CSVMessageBodyWriter implements MessageBodyWriter<List<Object>> { |  | ||||||
| 	public static final String CSV_TYPE = "text/csv"; |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) { |  | ||||||
| 		return List.class.isAssignableFrom(type); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public long getSize(final List<Object> data, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) { |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public void writeTo(final List<Object> data, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType, |  | ||||||
| 			final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException, WebApplicationException { |  | ||||||
| 		if (data != null && data.size() > 0) { |  | ||||||
| 			final CsvMapper mapper = new CsvMapper(); |  | ||||||
| 			final Object o = data.get(0); |  | ||||||
| 			final CsvSchema schema = mapper.schemaFor(o.getClass()).withHeader(); |  | ||||||
| 			mapper.writer(schema).writeValue(entityStream, data); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -12,12 +12,14 @@ 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.dataAccess.options.ReadAllColumn; | ||||||
| import org.kar.archidata.model.Data; | import org.kar.archidata.model.Data; | ||||||
| @@ -65,16 +67,6 @@ 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)), new ReadAllColumn()); | 			return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)), new ReadAllColumn()); | ||||||
| @@ -123,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); | ||||||
| @@ -133,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) { | ||||||
| @@ -219,7 +211,7 @@ 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); | ||||||
| @@ -230,7 +222,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(); | ||||||
| 			} | 			} | ||||||
| @@ -260,7 +252,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 ... "); | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								src/org/kar/archidata/tools/UuidUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/org/kar/archidata/tools/UuidUtils.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | package org.kar.archidata.tools; | ||||||
|  |  | ||||||
|  | import java.math.BigInteger; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | 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(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										246
									
								
								src/resources/rest-tools.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								src/resources/rest-tools.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | |||||||
|  | /** @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 urk or Header | ||||||
|  |     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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export type RESTRequestType = { | ||||||
|  |     restModel: RESTModel, | ||||||
|  |     restConfig: RESTConfig, | ||||||
|  |     data?: any, | ||||||
|  |     params?: object, | ||||||
|  |     queries?: object, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | function removeTrailingSlashes(input: string): string { | ||||||
|  |     return input.replace(/\/+$/, ''); | ||||||
|  | } | ||||||
|  | function removeLeadingSlashes(input: string): string { | ||||||
|  |     return input.replace(/^\/+/, ''); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function RESTUrl({ restModel, restConfig, data, 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 RESTRequest({ restModel, restConfig, data, params, queries }: 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 | ||||||
|  |     } | ||||||
|  |     console.log(`Call ${generateUrl}`) | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         fetch(generateUrl, { | ||||||
|  |             method: restModel.requestType, | ||||||
|  |             headers, | ||||||
|  |             body, | ||||||
|  |         }).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: "http-wrapper.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); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | } | ||||||
| @@ -1 +1 @@ | |||||||
| 0.6.3 | 0.7.0 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user