diff --git a/.checkstyle b/.checkstyle new file mode 100644 index 0000000..5783bc0 --- /dev/null +++ b/.checkstyle @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.classpath b/.classpath index 6c8fcb3..ccfe345 100644 --- a/.classpath +++ b/.classpath @@ -8,36 +8,20 @@ - - - - - - - - - - - - - - - - - - - + - - - - + + + + + + diff --git a/conditioningUnit b/conditioningUnit new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/conditioningUnit @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/pom.xml b/pom.xml index b6f3a1b..9949de5 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 kangaroo-and-rabbit archidata - 0.3.8 + 0.4.0 3.1.1 2.3.1 @@ -130,6 +130,17 @@ nimbus-jose-jwt 9.30 + + org.junit.jupiter + junit-jupiter-api + 5.7.2 + test + + + jakarta.persistence + jakarta.persistence-api + 3.1.0 + diff --git a/src/org/kar/archidata/GlobalConfiguration.java b/src/org/kar/archidata/GlobalConfiguration.java index eb3bab0..44024cc 100644 --- a/src/org/kar/archidata/GlobalConfiguration.java +++ b/src/org/kar/archidata/GlobalConfiguration.java @@ -16,3 +16,4 @@ public class GlobalConfiguration { ConfigBaseVariable.getDBKeepConnected()); } } + \ No newline at end of file diff --git a/src/org/kar/archidata/UpdateJwtPublicKey.java b/src/org/kar/archidata/UpdateJwtPublicKey.java index d4efdb0..d77dee3 100644 --- a/src/org/kar/archidata/UpdateJwtPublicKey.java +++ b/src/org/kar/archidata/UpdateJwtPublicKey.java @@ -5,14 +5,15 @@ import org.kar.archidata.util.JWTWrapper; public class UpdateJwtPublicKey extends Thread { boolean kill = false; + public void run() { if (ConfigBaseVariable.getSSOAddress() == null) { System.out.println("SSO INTERFACE is not provided ==> work alone."); // No SO provided, kill the thread. return; } - while (this.kill == false) { - // need to upgrade when server call us... + while (this.kill == false) { + // need to upgrade when server call us... try { JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata"); } catch (Exception e1) { @@ -22,12 +23,13 @@ public class UpdateJwtPublicKey extends Thread { } try { // update every 5 minutes the master token - Thread.sleep(1000*60*5, 0); + Thread.sleep(1000 * 60 * 5, 0); } catch (InterruptedException e) { e.printStackTrace(); } - } + } } + public void kill() { this.kill = true; } diff --git a/src/org/kar/archidata/UserDB.java b/src/org/kar/archidata/UserDB.java index a082861..326ec0c 100755 --- a/src/org/kar/archidata/UserDB.java +++ b/src/org/kar/archidata/UserDB.java @@ -1,45 +1,43 @@ package org.kar.archidata; -import org.kar.archidata.db.DBEntry; -import org.kar.archidata.model.User; -import org.kar.archidata.sqlWrapper.SqlWrapper; - import java.io.IOException; import java.sql.PreparedStatement; import java.sql.SQLException; +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.model.User; +import org.kar.archidata.sqlWrapper.SqlWrapper; + public class UserDB { - - public UserDB() { - } - - public static User getUsers(long userId) throws Exception { - return SqlWrapper.get(User.class, userId); - } - - - public static User getUserOrCreate(long userId, String userLogin) throws Exception { - User user = getUsers(userId); - if (user != null) { - return user; - } - createUsersInfoFromOAuth(userId, userLogin); - return getUsers(userId); - } - - private static void createUsersInfoFromOAuth(long userId, String login) throws IOException { - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')"; - try { - PreparedStatement ps = entry.connection.prepareStatement(query); - ps.setLong(1, userId); - ps.setString(2, login); - ps.executeUpdate(); - } catch (SQLException throwables) { - throwables.printStackTrace(); - } finally { - entry.close(); - } - } - + + public UserDB() {} + + public static User getUsers(long userId) throws Exception { + return SqlWrapper.get(User.class, userId); + } + + public static User getUserOrCreate(long userId, String userLogin) throws Exception { + User user = getUsers(userId); + if (user != null) { + return user; + } + createUsersInfoFromOAuth(userId, userLogin); + return getUsers(userId); + } + + private static void createUsersInfoFromOAuth(long userId, String login) throws IOException { + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, userId); + ps.setString(2, login); + ps.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } finally { + entry.close(); + } + } + } diff --git a/src/org/kar/archidata/annotation/AnnotationTools.java b/src/org/kar/archidata/annotation/AnnotationTools.java new file mode 100644 index 0000000..afc0b32 --- /dev/null +++ b/src/org/kar/archidata/annotation/AnnotationTools.java @@ -0,0 +1,129 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.persistence.Column; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Table; + +public class AnnotationTools { + static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class); + + public static String getTableName(final Class element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @SQLTableName on " + element.getClass().getCanonicalName()); + } + final String tmp = ((Table) annotation[0]).name(); + if (tmp == null) { + return null; + } + return tmp; + } + + public static String getComment(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLComment.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @SQLComment on " + element.getClass().getCanonicalName()); + } + final String tmp = ((SQLComment) annotation[0]).value(); + if (tmp == null) { + return null; + } + return tmp; + } + + public static String getDefault(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLDefault.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @SQLDefault on " + element.getClass().getCanonicalName()); + } + final String tmp = ((SQLDefault) annotation[0]).value(); + if (tmp == null) { + return null; + } + return tmp; + } + + public static Integer getLimitSize(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @SQLLimitSize on " + element.getClass().getCanonicalName()); + } + return ((Column) annotation[0]).length(); + } + + public static boolean isAnnotationGroup(final Field field, final Class annotationType) { + try { + final Annotation[] anns = field.getAnnotations(); + for (final Annotation ann : anns) { + if (ann.annotationType() == annotationType) { + return true; + } + } + for (final Annotation ann : anns) { + final Annotation[] anns2 = ann.annotationType().getDeclaredAnnotations(); + for (final Annotation ann2 : anns2) { + if (ann2.annotationType() == annotationType) { + return true; + } + } + } + } catch (final Exception ex) { + LOGGER.error("Catch exception when try to get annotation...{}", ex.getLocalizedMessage()); + return false; + } + return false; + } + + public static boolean getNotNull(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); + if (annotation.length == 0) { + return true; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName()); + } + return ((Column) annotation[0]).nullable(); + } + + public static boolean isPrimaryKey(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); + if (annotation.length == 0) { + return true; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName()); + } + return ((Column) annotation[0]).unique(); + } + + public static GenerationType getStrategy(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName()); + } + return ((GeneratedValue) annotation[0]).strategy(); + } + +} diff --git a/src/org/kar/archidata/annotation/SQLCreateTime.java b/src/org/kar/archidata/annotation/CreationTimestamp.java similarity index 86% rename from src/org/kar/archidata/annotation/SQLCreateTime.java rename to src/org/kar/archidata/annotation/CreationTimestamp.java index 51dfdec..ac04d4f 100644 --- a/src/org/kar/archidata/annotation/SQLCreateTime.java +++ b/src/org/kar/archidata/annotation/CreationTimestamp.java @@ -7,6 +7,6 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -public @interface SQLCreateTime { - +public @interface CreationTimestamp { + } diff --git a/src/org/kar/archidata/annotation/SQLPrimaryKey.java b/src/org/kar/archidata/annotation/SQLAddOn.java similarity index 77% rename from src/org/kar/archidata/annotation/SQLPrimaryKey.java rename to src/org/kar/archidata/annotation/SQLAddOn.java index 60944cf..c1c5037 100644 --- a/src/org/kar/archidata/annotation/SQLPrimaryKey.java +++ b/src/org/kar/archidata/annotation/SQLAddOn.java @@ -5,8 +5,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Target(ElementType.FIELD) +@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface SQLPrimaryKey { - +public @interface SQLAddOn { + } diff --git a/src/org/kar/archidata/annotation/SQLComment.java b/src/org/kar/archidata/annotation/SQLComment.java index 9bfa21f..e05df17 100644 --- a/src/org/kar/archidata/annotation/SQLComment.java +++ b/src/org/kar/archidata/annotation/SQLComment.java @@ -8,7 +8,7 @@ import java.lang.annotation.Target; @Target({ ElementType.TYPE, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface SQLComment { - + String value(); - + } diff --git a/src/org/kar/archidata/annotation/SQLDefault.java b/src/org/kar/archidata/annotation/SQLDefault.java index ec88f2e..fd96353 100644 --- a/src/org/kar/archidata/annotation/SQLDefault.java +++ b/src/org/kar/archidata/annotation/SQLDefault.java @@ -8,7 +8,7 @@ import java.lang.annotation.Target; @Target({ ElementType.TYPE, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface SQLDefault { - + String value(); - + } diff --git a/src/org/kar/archidata/annotation/SQLDeleted.java b/src/org/kar/archidata/annotation/SQLDeleted.java index 681700a..84f0359 100644 --- a/src/org/kar/archidata/annotation/SQLDeleted.java +++ b/src/org/kar/archidata/annotation/SQLDeleted.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLDeleted { - + } diff --git a/src/org/kar/archidata/annotation/SQLIfNotExists.java b/src/org/kar/archidata/annotation/SQLIfNotExists.java index 9b185d6..68b4590 100644 --- a/src/org/kar/archidata/annotation/SQLIfNotExists.java +++ b/src/org/kar/archidata/annotation/SQLIfNotExists.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SQLIfNotExists { - + } diff --git a/src/org/kar/archidata/annotation/SQLLimitSize.java b/src/org/kar/archidata/annotation/SQLLimitSize.java deleted file mode 100644 index 5ed10c4..0000000 --- a/src/org/kar/archidata/annotation/SQLLimitSize.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.kar.archidata.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface SQLLimitSize { - int value(); -} diff --git a/src/org/kar/archidata/annotation/SQLNotRead.java b/src/org/kar/archidata/annotation/SQLNotRead.java index 50bb67b..a67bd72 100644 --- a/src/org/kar/archidata/annotation/SQLNotRead.java +++ b/src/org/kar/archidata/annotation/SQLNotRead.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLNotRead { - + } diff --git a/src/org/kar/archidata/annotation/SQLTableName.java b/src/org/kar/archidata/annotation/SQLTableName.java deleted file mode 100644 index 5902edc..0000000 --- a/src/org/kar/archidata/annotation/SQLTableName.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.kar.archidata.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface SQLTableName { - - String value(); - -} diff --git a/src/org/kar/archidata/annotation/SQLUpdateTime.java b/src/org/kar/archidata/annotation/SQLUpdateTime.java deleted file mode 100644 index fe2ecad..0000000 --- a/src/org/kar/archidata/annotation/SQLUpdateTime.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.kar.archidata.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface SQLUpdateTime { - -} diff --git a/src/org/kar/archidata/annotation/SQLAutoIncrement.java b/src/org/kar/archidata/annotation/UpdateTimestamp.java similarity index 87% rename from src/org/kar/archidata/annotation/SQLAutoIncrement.java rename to src/org/kar/archidata/annotation/UpdateTimestamp.java index 8c22c7d..ec980a5 100644 --- a/src/org/kar/archidata/annotation/SQLAutoIncrement.java +++ b/src/org/kar/archidata/annotation/UpdateTimestamp.java @@ -7,6 +7,6 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -public @interface SQLAutoIncrement { - +public @interface UpdateTimestamp { + } diff --git a/src/org/kar/archidata/annotation/SQLNotNull.java b/src/org/kar/archidata/annotation/addOn/SQLTableExternalForeinKeyAsList.java similarity index 59% rename from src/org/kar/archidata/annotation/SQLNotNull.java rename to src/org/kar/archidata/annotation/addOn/SQLTableExternalForeinKeyAsList.java index 07a20aa..7fc59cf 100644 --- a/src/org/kar/archidata/annotation/SQLNotNull.java +++ b/src/org/kar/archidata/annotation/addOn/SQLTableExternalForeinKeyAsList.java @@ -1,12 +1,15 @@ -package org.kar.archidata.annotation; +package org.kar.archidata.annotation.addOn; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.kar.archidata.annotation.SQLAddOn; + @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -public @interface SQLNotNull { - +@SQLAddOn +public @interface SQLTableExternalForeinKeyAsList { + } diff --git a/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java b/src/org/kar/archidata/annotation/addOn/SQLTableExternalLink.java similarity index 65% rename from src/org/kar/archidata/annotation/SQLTableLinkGeneric.java rename to src/org/kar/archidata/annotation/addOn/SQLTableExternalLink.java index e2cbcc6..94bb6fb 100644 --- a/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java +++ b/src/org/kar/archidata/annotation/addOn/SQLTableExternalLink.java @@ -1,32 +1,28 @@ -package org.kar.archidata.annotation; +package org.kar.archidata.annotation.addOn; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; - - +import org.kar.archidata.annotation.SQLAddOn; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -public @interface SQLTableLinkGeneric { - public static String AUTOMATIC ="__auto__"; - public enum ModelLink { - NONE, - INTERNAL, // The list is serialized in a string ',' separated - EXTERNAL // an external table is created and - }; - // Permit to select the link mode. - ModelLink value() default ModelLink.EXTERNAL; - // If automatic table name, the table name is: parentTableName_externalTableName__link +@SQLAddOn +public @interface SQLTableExternalLink { + public static String AUTOMATIC = "__auto__"; + + // If automatic table name, the table name is: parentTableName_externalTableName__link String tableName() default AUTOMATIC; + // If automatic table name, the name of the foreign table is manage with the variable name. String externalTableName() default AUTOMATIC; + // If the external link have a field to filter with a specific value (name of the field) String filterField() default AUTOMATIC; + // If the external link have a field to filter with a specific value (value of the field) String filterValue() default AUTOMATIC; - } diff --git a/src/org/kar/archidata/annotation/security/DenyAll.java b/src/org/kar/archidata/annotation/security/DenyAll.java index ede47ab..f5253df 100644 --- a/src/org/kar/archidata/annotation/security/DenyAll.java +++ b/src/org/kar/archidata/annotation/security/DenyAll.java @@ -1,15 +1,14 @@ package org.kar.archidata.annotation.security; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import java.lang.annotation.Retention; import java.lang.annotation.Target; import jakarta.ws.rs.NameBinding; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - @NameBinding @Retention(RUNTIME) -@Target({METHOD}) -public @interface DenyAll { -} +@Target({ METHOD }) +public @interface DenyAll {} diff --git a/src/org/kar/archidata/annotation/security/PermitAll.java b/src/org/kar/archidata/annotation/security/PermitAll.java index ea5e210..7077eb9 100644 --- a/src/org/kar/archidata/annotation/security/PermitAll.java +++ b/src/org/kar/archidata/annotation/security/PermitAll.java @@ -1,14 +1,14 @@ package org.kar.archidata.annotation.security; -import jakarta.ws.rs.NameBinding; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.ws.rs.NameBinding; + @NameBinding @Retention(RUNTIME) -@Target({METHOD}) -public @interface PermitAll { -} +@Target({ METHOD }) +public @interface PermitAll {} diff --git a/src/org/kar/archidata/annotation/security/PermitTokenInURI.java b/src/org/kar/archidata/annotation/security/PermitTokenInURI.java index f1f6404..62f43d8 100644 --- a/src/org/kar/archidata/annotation/security/PermitTokenInURI.java +++ b/src/org/kar/archidata/annotation/security/PermitTokenInURI.java @@ -1,14 +1,14 @@ package org.kar.archidata.annotation.security; -import jakarta.ws.rs.NameBinding; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.ws.rs.NameBinding; + @NameBinding @Retention(RUNTIME) -@Target({METHOD}) -public @interface PermitTokenInURI { -} +@Target({ METHOD }) +public @interface PermitTokenInURI {} diff --git a/src/org/kar/archidata/annotation/security/RolesAllowed.java b/src/org/kar/archidata/annotation/security/RolesAllowed.java index 9cb18be..662f11a 100644 --- a/src/org/kar/archidata/annotation/security/RolesAllowed.java +++ b/src/org/kar/archidata/annotation/security/RolesAllowed.java @@ -1,15 +1,16 @@ package org.kar.archidata.annotation.security; -import jakarta.ws.rs.NameBinding; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.ws.rs.NameBinding; + @NameBinding @Retention(RUNTIME) -@Target({METHOD}) +@Target({ METHOD }) public @interface RolesAllowed { String[] value(); } diff --git a/src/org/kar/archidata/api/DataResource.java b/src/org/kar/archidata/api/DataResource.java index 8a696c9..8db3e2a 100644 --- a/src/org/kar/archidata/api/DataResource.java +++ b/src/org/kar/archidata/api/DataResource.java @@ -1,12 +1,32 @@ package org.kar.archidata.api; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Date; + +import javax.imageio.ImageIO; + import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -import org.kar.archidata.filter.GenericContext; -import org.kar.archidata.model.Data; -import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.annotation.security.PermitTokenInURI; import org.kar.archidata.annotation.security.RolesAllowed; +import org.kar.archidata.filter.GenericContext; +import org.kar.archidata.model.Data; +import org.kar.archidata.sqlWrapper.QuerryCondition; +import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.util.ConfigBaseVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,413 +48,376 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.SecurityContext; import jakarta.ws.rs.core.StreamingOutput; -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Date; - - // https://stackoverflow.com/questions/35367113/jersey-webservice-scalable-approach-to-download-file-and-reply-to-client // https://gist.github.com/aitoroses/4f7a2b197b732a6a691d @Path("/data") @Produces(MediaType.APPLICATION_JSON) public class DataResource { - static final Logger logger = LoggerFactory.getLogger(MediaType.class); - private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks - private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks - /** - * Upload some datas - */ - private static long tmpFolderId = 1; - - private static void createFolder(String path) throws IOException { - if (!Files.exists(java.nio.file.Path.of(path))) { - //Log.print("Create folder: " + path); - Files.createDirectories(java.nio.file.Path.of(path)); - } - } - - public static long getTmpDataId() { - return tmpFolderId++; - } - - public static String getTmpFileInData(long tmpFolderId) { - String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId; - try { - createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); - } catch (IOException e) { - e.printStackTrace(); - } - return filePath; - } - - public static String getFileData(long tmpFolderId) { - String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; - try { - createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); - } catch (IOException e) { - e.printStackTrace(); - } - return filePath; - } - - public static Data getWithSha512(String sha512) { - logger.info("find sha512 = {}", sha512); - try { - return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512); + private static final Logger LOGGER = LoggerFactory.getLogger(MediaType.class); + private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks + private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks + /** + * Upload some datas + */ + private static long tmpFolderId = 1; + + private static void createFolder(String path) throws IOException { + if (!Files.exists(java.nio.file.Path.of(path))) { + //Log.print("Create folder: " + path); + Files.createDirectories(java.nio.file.Path.of(path)); + } + } + + public static long getTmpDataId() { + return tmpFolderId++; + } + + public static String getTmpFileInData(long tmpFolderId) { + String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId; + try { + createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static String getFileData(long tmpFolderId) { + String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; + try { + createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static Data getWithSha512(String sha512) { + LOGGER.info("find sha512 = {}", sha512); + try { + return SqlWrapper.getWhere(Data.class, new QuerryCondition("sha512", "=", sha512)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - return null; - } - - public static Data getWithId(long id) { - logger.info("find id = {}", id); - try { + return null; + } + + public static Data getWithId(long id) { + LOGGER.info("find id = {}", id); + try { return SqlWrapper.get(Data.class, id); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - return null; - } - - public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException { - // determine mime type: - Data injectedData = new Data(); - String mimeType = ""; - String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); - switch (extension.toLowerCase()) { - case "jpg": - case "jpeg": - mimeType = "image/jpeg"; - break; - case "png": - mimeType = "image/png"; - break; - case "webp": - mimeType = "image/webp"; - break; - case "mka": - mimeType = "audio/x-matroska"; - break; - case "mkv": - mimeType = "video/x-matroska"; - break; - case "webm": - mimeType = "video/webm"; - break; - default: - throw new IOException("Can not find the mime type of data input: '" + extension + "'"); - } - injectedData.mimeType = mimeType; - injectedData.sha512 = sha512; - String tmpPath = getTmpFileInData(tmpUID); - injectedData.size = Files.size(Paths.get(tmpPath)); - - try { - injectedData = SqlWrapper.insert(injectedData); + return null; + } + + public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException { + // determine mime type: + Data injectedData = new Data(); + String mimeType = ""; + String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); + switch (extension.toLowerCase()) { + case "jpg": + case "jpeg": + mimeType = "image/jpeg"; + break; + case "png": + mimeType = "image/png"; + break; + case "webp": + mimeType = "image/webp"; + break; + case "mka": + mimeType = "audio/x-matroska"; + break; + case "mkv": + mimeType = "video/x-matroska"; + break; + case "webm": + mimeType = "video/webm"; + break; + default: + throw new IOException("Can not find the mime type of data input: '" + extension + "'"); + } + injectedData.mimeType = mimeType; + injectedData.sha512 = sha512; + String tmpPath = getTmpFileInData(tmpUID); + injectedData.size = Files.size(Paths.get(tmpPath)); + + try { + injectedData = SqlWrapper.insert(injectedData); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } - String mediaPath = getFileData(injectedData.id); - logger.info("src = {}", tmpPath); - logger.info("dst = {}", mediaPath); - Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); - logger.info("Move done"); - return injectedData; - } - - public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) { - return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData)); - } - - public static void removeTemporaryFile(long idData) { - String filepath = DataResource.getTmpFileInData(idData); - if (Files.exists(Paths.get(filepath))) { - try { - Files.delete(Paths.get(filepath)); - } catch (IOException e) { - logger.info("can not delete temporary file : {}", Paths.get(filepath)); - e.printStackTrace(); - } - } - } - - // save uploaded file to a defined location on the server - static String saveFile(InputStream uploadedInputStream, String serverLocation) { - String out = ""; - try { - OutputStream outpuStream = new FileOutputStream(new File( - serverLocation)); - int read = 0; - byte[] bytes = new byte[CHUNK_SIZE_IN]; - MessageDigest md = MessageDigest.getInstance("SHA-512"); - - outpuStream = new FileOutputStream(new File(serverLocation)); - while ((read = uploadedInputStream.read(bytes)) != -1) { - //logger.info("write {}", read); - md.update(bytes, 0, read); - outpuStream.write(bytes, 0, read); - } - logger.info("Flush input stream ... {}", serverLocation); - System.out.flush(); - outpuStream.flush(); - outpuStream.close(); - // create the end of sha512 - byte[] sha512Digest = md.digest(); - // convert in hexadecimal - out = bytesToHex(sha512Digest); - uploadedInputStream.close(); - } catch (IOException ex) { - logger.info("Can not write in temporary file ... "); - ex.printStackTrace(); - } catch (NoSuchAlgorithmException ex) { - logger.info("Can not find sha512 algorithms"); - ex.printStackTrace(); - } - return out; - } - - public static String bytesToHex(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(String.format("%02x", b)); - } - return sb.toString(); - } - - - public Data getSmall(Long id) { - try { + String mediaPath = getFileData(injectedData.id); + LOGGER.info("src = {}", tmpPath); + LOGGER.info("dst = {}", mediaPath); + Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); + LOGGER.info("Move done"); + return injectedData; + } + + public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) { + return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData)); + } + + public static void removeTemporaryFile(long idData) { + String filepath = DataResource.getTmpFileInData(idData); + if (Files.exists(Paths.get(filepath))) { + try { + Files.delete(Paths.get(filepath)); + } catch (IOException e) { + LOGGER.info("can not delete temporary file : {}", Paths.get(filepath)); + e.printStackTrace(); + } + } + } + + // save uploaded file to a defined location on the server + static String saveFile(InputStream uploadedInputStream, String serverLocation) { + String out = ""; + try { + OutputStream outpuStream = new FileOutputStream(new File(serverLocation)); + int read = 0; + byte[] bytes = new byte[CHUNK_SIZE_IN]; + MessageDigest md = MessageDigest.getInstance("SHA-512"); + + outpuStream = new FileOutputStream(new File(serverLocation)); + while ((read = uploadedInputStream.read(bytes)) != -1) { + //logger.info("write {}", read); + md.update(bytes, 0, read); + outpuStream.write(bytes, 0, read); + } + LOGGER.info("Flush input stream ... {}", serverLocation); + System.out.flush(); + outpuStream.flush(); + outpuStream.close(); + // create the end of sha512 + byte[] sha512Digest = md.digest(); + // convert in hexadecimal + out = bytesToHex(sha512Digest); + uploadedInputStream.close(); + } catch (IOException ex) { + LOGGER.info("Can not write in temporary file ... "); + ex.printStackTrace(); + } catch (NoSuchAlgorithmException ex) { + LOGGER.info("Can not find sha512 algorithms"); + ex.printStackTrace(); + } + return out; + } + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + public Data getSmall(Long id) { + try { return SqlWrapper.get(Data.class, id); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - return null; - } - - @POST - @Path("/upload/") - @Consumes({MediaType.MULTIPART_FORM_DATA}) - @RolesAllowed("ADMIN") - public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) { - GenericContext gc = (GenericContext) sc.getUserPrincipal(); - logger.info("==================================================="); - logger.info("== DATA uploadFile {}", (gc==null?"null":gc.userByToken)); - logger.info("==================================================="); - //public NodeSmall uploadFile(final FormDataMultiPart form) { - logger.info("Upload file: "); - String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++; - try { - createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); - } catch (IOException e) { - e.printStackTrace(); - } - saveFile(fileInputStream, filePath); - return Response.ok("Data uploaded successfully !!").build(); - //return null; - } - - @GET - @Path("{id}") - @PermitTokenInURI - @RolesAllowed("USER") - @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception { - GenericContext gc = (GenericContext) sc.getUserPrincipal(); - //logger.info("==================================================="); - logger.info("== DATA retriveDataId ? id={} user={}", id, (gc==null?"null":gc.userByToken)); - //logger.info("==================================================="); - Data value = getSmall(id); - if (value == null) { - 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); - } - - @GET - @Path("thumbnail/{id}") - @RolesAllowed("USER") - @PermitTokenInURI - @Produces(MediaType.APPLICATION_OCTET_STREAM) - //@CacheMaxAge(time = 10, unit = TimeUnit.DAYS) - public Response retriveDataThumbnailId(@Context SecurityContext sc, - @QueryParam(HttpHeaders.AUTHORIZATION) String token, - @HeaderParam("Range") String range, - @PathParam("id") Long id) throws Exception { - //GenericContext gc = (GenericContext) sc.getUserPrincipal(); - //logger.info("==================================================="); - //logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user)); - //logger.info("==================================================="); - Data value = getSmall(id); - if (value == null) { - return Response.status(404). - entity("media NOT FOUND: " + id). - type("text/plain"). - build(); - } - String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data"; - File inputFile = new File(filePathName); - if (!inputFile.exists()) { - return Response.status(404). - entity("{\"error\":\"media Does not exist: " + id + "\"}"). - type("application/json"). - build(); - } - if ( value.mimeType.contentEquals("image/jpeg") - || value.mimeType.contentEquals("image/png") - // || value.mimeType.contentEquals("image/webp") - ) { - // reads input image - BufferedImage inputImage = ImageIO.read(inputFile); - int scaledWidth = 250; - int scaledHeight = (int)((float)inputImage.getHeight() / (float)inputImage.getWidth() * (float) scaledWidth); - // creates output image - BufferedImage outputImage = new BufferedImage(scaledWidth, - scaledHeight, inputImage.getType()); - - // scales the input image to the output image - Graphics2D g2d = outputImage.createGraphics(); - g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null); - g2d.dispose(); - // create the output stream: - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - // TODO: check how to remove buffer file !!! here, it is not needed at all... - ImageIO.write( outputImage, "JPG", baos); + return null; + } + + @POST + @Path("/upload/") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @RolesAllowed("ADMIN") + public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) { + GenericContext gc = (GenericContext) sc.getUserPrincipal(); + LOGGER.info("==================================================="); + LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken)); + LOGGER.info("==================================================="); + //public NodeSmall uploadFile(final FormDataMultiPart form) { + LOGGER.info("Upload file: "); + String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++; + try { + createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + saveFile(fileInputStream, filePath); + return Response.ok("Data uploaded successfully !!").build(); + //return null; + } + + @GET + @Path("{id}") + @PermitTokenInURI + @RolesAllowed("USER") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception { + GenericContext gc = (GenericContext) sc.getUserPrincipal(); + //logger.info("==================================================="); + LOGGER.info("== DATA retriveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken)); + //logger.info("==================================================="); + Data value = getSmall(id); + if (value == null) { + 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); + } + + @GET + @Path("thumbnail/{id}") + @RolesAllowed("USER") + @PermitTokenInURI + @Produces(MediaType.APPLICATION_OCTET_STREAM) + //@CacheMaxAge(time = 10, unit = TimeUnit.DAYS) + public Response retriveDataThumbnailId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) + throws Exception { + //GenericContext gc = (GenericContext) sc.getUserPrincipal(); + //logger.info("==================================================="); + //logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user)); + //logger.info("==================================================="); + Data value = getSmall(id); + if (value == null) { + return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build(); + } + String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data"; + File inputFile = new File(filePathName); + if (!inputFile.exists()) { + return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build(); + } + if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png") + // || value.mimeType.contentEquals("image/webp") + ) { + // reads input image + BufferedImage inputImage = ImageIO.read(inputFile); + int scaledWidth = 250; + int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() * (float) scaledWidth); + // creates output image + BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType()); + + // scales the input image to the output image + Graphics2D g2d = outputImage.createGraphics(); + g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null); + g2d.dispose(); + // create the output stream: + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + // TODO: check how to remove buffer file !!! here, it is not needed at all... + ImageIO.write(outputImage, "JPG", baos); } catch (IOException e) { e.printStackTrace(); - return Response.status(500). - entity("Internal Error: resize fail: " + e.getMessage()). - type("text/plain"). - build(); + return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain").build(); } - byte[] imageData = baos.toByteArray(); - //Response.ok(new ByteArrayInputStream(imageData)).build(); - Response.ResponseBuilder out = Response.ok(imageData) - .header(HttpHeaders.CONTENT_LENGTH, imageData.length); - out.type("image/jpeg"); - // TODO: move this in a decorator !!! - CacheControl cc = new CacheControl(); - cc.setMaxAge(3600); - cc.setNoCache(false); - out.cacheControl(cc); - return out.build(); - } - return buildStream(filePathName, range, value.mimeType); - } - //@Secured - @GET - @Path("{id}/{name}") - @PermitTokenInURI - @RolesAllowed("USER") - @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id, @PathParam("name") String name) throws Exception { - GenericContext gc = (GenericContext) sc.getUserPrincipal(); - //logger.info("==================================================="); - logger.info("== DATA retriveDataFull ? id={} user={}", id, (gc==null?"null":gc.userByToken)); - //logger.info("==================================================="); - Data value = getSmall(id); - if (value == null) { - 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); - } - - /** - * Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541 - * - * @param range range header - * @return Streaming output - * @throws Exception IOException if an error occurs in streaming. - */ - private Response buildStream(final String filename, final String range, String mimeType) throws Exception { - File file = new File(filename); - //logger.info("request range : {}", range); - // range not requested : Firefox does not send range headers - if (range == null) { - final StreamingOutput output = new StreamingOutput() { - @Override - public void write(OutputStream out) { - try (FileInputStream in = new FileInputStream(file)) { - byte[] buf = new byte[1024 * 1024]; - int len; - while ((len = in.read(buf)) != -1) { - try { - out.write(buf, 0, len); - out.flush(); - //logger.info("---- wrote {} bytes file ----", len); - } catch (IOException ex) { - logger.info("remote close connection"); - break; - } - } - } catch (IOException ex) { - throw new InternalServerErrorException(ex); - } - } - }; - Response.ResponseBuilder out = Response.ok(output) - .header(HttpHeaders.CONTENT_LENGTH, file.length()); - if (mimeType != null) { - out.type(mimeType); - } - return out.build(); - - } - - String[] ranges = range.split("=")[1].split("-"); - final long from = Long.parseLong(ranges[0]); - - //logger.info("request range : {}", ranges.length); - //Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-" - long to = CHUNK_SIZE + from; - if (ranges.length == 1) { - to = file.length() - 1; - } else { - if (to >= file.length()) { - to = (long) (file.length() - 1); - } - } - final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length()); - //logger.info("responseRange: {}", responseRange); - final RandomAccessFile raf = new RandomAccessFile(file, "r"); - raf.seek(from); - - final long len = to - from + 1; - final MediaStreamer streamer = new MediaStreamer(len, raf); - Response.ResponseBuilder out = Response.ok(streamer) - .status(Response.Status.PARTIAL_CONTENT) - .header("Accept-Ranges", "bytes") - .header("Content-Range", responseRange) - .header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth()) - .header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified())); - if (mimeType != null) { - out.type(mimeType); - } - return out.build(); - } - + byte[] imageData = baos.toByteArray(); + //Response.ok(new ByteArrayInputStream(imageData)).build(); + Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, imageData.length); + out.type("image/jpeg"); + // TODO: move this in a decorator !!! + CacheControl cc = new CacheControl(); + cc.setMaxAge(3600); + cc.setNoCache(false); + out.cacheControl(cc); + return out.build(); + } + return buildStream(filePathName, range, value.mimeType); + } + + //@Secured + @GET + @Path("{id}/{name}") + @PermitTokenInURI + @RolesAllowed("USER") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id, + @PathParam("name") String name) throws Exception { + GenericContext gc = (GenericContext) sc.getUserPrincipal(); + //logger.info("==================================================="); + LOGGER.info("== DATA retriveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken)); + //logger.info("==================================================="); + Data value = getSmall(id); + if (value == null) { + 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); + } + + /** + * Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541 + * + * @param range range header + * @return Streaming output + * @throws Exception IOException if an error occurs in streaming. + */ + private Response buildStream(final String filename, final String range, String mimeType) throws Exception { + File file = new File(filename); + //logger.info("request range : {}", range); + // range not requested : Firefox does not send range headers + if (range == null) { + final StreamingOutput output = new StreamingOutput() { + @Override + public void write(OutputStream out) { + try (FileInputStream in = new FileInputStream(file)) { + byte[] buf = new byte[1024 * 1024]; + int len; + while ((len = in.read(buf)) != -1) { + try { + out.write(buf, 0, len); + out.flush(); + //logger.info("---- wrote {} bytes file ----", len); + } catch (IOException ex) { + LOGGER.info("remote close connection"); + break; + } + } + } catch (IOException ex) { + throw new InternalServerErrorException(ex); + } + } + }; + Response.ResponseBuilder out = Response.ok(output).header(HttpHeaders.CONTENT_LENGTH, file.length()); + if (mimeType != null) { + out.type(mimeType); + } + return out.build(); + + } + + String[] ranges = range.split("=")[1].split("-"); + final long from = Long.parseLong(ranges[0]); + + //logger.info("request range : {}", ranges.length); + //Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-" + long to = CHUNK_SIZE + from; + if (ranges.length == 1) { + to = file.length() - 1; + } else { + if (to >= file.length()) { + to = (long) (file.length() - 1); + } + } + final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length()); + //logger.info("responseRange: {}", responseRange); + final RandomAccessFile raf = new RandomAccessFile(file, "r"); + raf.seek(from); + + final long len = to - from + 1; + final MediaStreamer streamer = new MediaStreamer(len, raf); + Response.ResponseBuilder out = Response.ok(streamer).status(Response.Status.PARTIAL_CONTENT).header("Accept-Ranges", "bytes").header("Content-Range", responseRange) + .header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth()).header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified())); + if (mimeType != null) { + out.type(mimeType); + } + return out.build(); + } + public static void undelete(Long id) throws Exception { SqlWrapper.unsetDelete(Data.class, id); } - + } diff --git a/src/org/kar/archidata/api/FrontGeneric.java b/src/org/kar/archidata/api/FrontGeneric.java index d570349..3af6a77 100644 --- a/src/org/kar/archidata/api/FrontGeneric.java +++ b/src/org/kar/archidata/api/FrontGeneric.java @@ -3,100 +3,110 @@ package org.kar.archidata.api; import java.io.File; import java.util.List; -import jakarta.ws.rs.*; +import org.kar.archidata.annotation.security.PermitAll; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.NotSupportedException; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; import jakarta.ws.rs.core.CacheControl; import jakarta.ws.rs.core.PathSegment; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.ResponseBuilder; -import org.kar.archidata.annotation.security.PermitAll; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - public class FrontGeneric { - static final Logger logger = LoggerFactory.getLogger(FrontGeneric.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FrontGeneric.class); protected String baseFrontFolder = "/data/front"; private String getExtension(String filename) { - if (filename.contains(".")) { - return filename.substring(filename.lastIndexOf(".") + 1); - } - return ""; + if (filename.contains(".")) { + return filename.substring(filename.lastIndexOf(".") + 1); + } + return ""; + } + + private Response retrive(String fileName) throws Exception { + String filePathName = baseFrontFolder + File.separator + fileName; + String extention = getExtension(filePathName); + String mineType = null; + LOGGER.debug("try retrive : '{}' '{}'", filePathName, extention); + if (extention.length() != 0 && extention.length() <= 5) { + if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) { + mineType = "image/jpeg"; + } else if (extention.equalsIgnoreCase("gif")) { + mineType = "image/gif"; + } else if (extention.equalsIgnoreCase("png")) { + mineType = "image/png"; + } else if (extention.equalsIgnoreCase("svg")) { + mineType = "image/svg+xml"; + } else if (extention.equalsIgnoreCase("webp")) { + mineType = "image/webp"; + } else if (extention.equalsIgnoreCase("js")) { + mineType = "application/javascript"; + } else if (extention.equalsIgnoreCase("json")) { + mineType = "application/json"; + } else if (extention.equalsIgnoreCase("ico")) { + mineType = "image/x-icon"; + } else if (extention.equalsIgnoreCase("html")) { + mineType = "text/html"; + } else if (extention.equalsIgnoreCase("css")) { + mineType = "text/css"; + } else if (extention.equalsIgnoreCase("mka")) { + mineType = "audio/x-matroska"; + } else if (extention.equalsIgnoreCase("mkv")) { + mineType = "video/x-matroska"; + } else if (extention.equalsIgnoreCase("webm")) { + mineType = "video/webm"; + } else { + throw new NotSupportedException("Not supported model: '" + fileName + "'"); + } + } else { + mineType = "text/html"; + filePathName = baseFrontFolder + File.separator + "index.html"; + } + LOGGER.debug(" ==> '[}'", filePathName); + // reads input image + File download = new File(filePathName); + if (!download.exists()) { + throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'"); + } + ResponseBuilder response = Response.ok((Object) download); + // use this if I want to download the file: + //response.header("Content-Disposition", "attachment; filename=" + fileName); + CacheControl cc = new CacheControl(); + cc.setMaxAge(60); + cc.setNoCache(false); + response.cacheControl(cc); + response.type(mineType); + + return response.build(); + } + + @GET + @PermitAll() + //@Produces(MediaType.APPLICATION_OCTET_STREAM) + //@CacheMaxAge(time = 1, unit = TimeUnit.DAYS) + public Response retrive0() throws Exception { + return retrive("index.html"); + } + + @GET + @Path("{any: .*}") + @PermitAll() + //@Produces(MediaType.APPLICATION_OCTET_STREAM) + //@CacheMaxAge(time = 10, unit = TimeUnit.DAYS) + public Response retrive1(@PathParam("any") List segments) throws Exception { + String filename = ""; + for (PathSegment elem : segments) { + if (!filename.isEmpty()) { + filename += File.separator; + } + filename += elem.getPath(); + } + return retrive(filename); } - private Response retrive(String fileName) throws Exception { - String filePathName = baseFrontFolder + File.separator + fileName; - String extention = getExtension(filePathName); - String mineType = null; - logger.debug("try retrive : '{}' '{}'", filePathName, extention); - if (extention.length() !=0 && extention.length() <= 5) { - if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) { - mineType = "image/jpeg"; - } else if (extention.equalsIgnoreCase("gif")) { - mineType = "image/gif"; - } else if (extention.equalsIgnoreCase("png")) { - mineType = "image/png"; - } else if (extention.equalsIgnoreCase("svg")) { - mineType = "image/svg+xml"; - } else if (extention.equalsIgnoreCase("webp")) { - mineType = "image/webp"; - } else if (extention.equalsIgnoreCase("js")) { - mineType = "application/javascript"; - } else if (extention.equalsIgnoreCase("json")) { - mineType = "application/json"; - } else if (extention.equalsIgnoreCase("ico")) { - mineType = "image/x-icon"; - } else if (extention.equalsIgnoreCase("html")) { - mineType = "text/html"; - } else if (extention.equalsIgnoreCase("css")) { - mineType = "text/css"; - } else { - throw new NotSupportedException("Not supported model: '" + fileName + "'"); - } - } else { - mineType = "text/html"; - filePathName = baseFrontFolder + File.separator + "index.html"; - } - logger.debug(" ==> '[}'", filePathName); - // reads input image - File download = new File(filePathName); - if (!download.exists()) { - throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'"); - } - ResponseBuilder response = Response.ok((Object)download); - // use this if I want to download the file: - //response.header("Content-Disposition", "attachment; filename=" + fileName); - CacheControl cc = new CacheControl(); - cc.setMaxAge(60); - cc.setNoCache(false); - response.cacheControl(cc); - response.type(mineType); - - return response.build(); - } - - @GET - @PermitAll() - //@Produces(MediaType.APPLICATION_OCTET_STREAM) - //@CacheMaxAge(time = 1, unit = TimeUnit.DAYS) - public Response retrive0() throws Exception { - return retrive("index.html"); - } - - @GET - @Path("{any: .*}") - @PermitAll() - //@Produces(MediaType.APPLICATION_OCTET_STREAM) - //@CacheMaxAge(time = 10, unit = TimeUnit.DAYS) - public Response retrive1(@PathParam("any") List segments) throws Exception { - String filename = ""; - for (PathSegment elem: segments) { - if (!filename.isEmpty()) { - filename += File.separator; - } - filename += elem.getPath(); - } - return retrive(filename); - } } diff --git a/src/org/kar/archidata/api/MediaStreamer.java b/src/org/kar/archidata/api/MediaStreamer.java index 6262bbb..15d7d93 100644 --- a/src/org/kar/archidata/api/MediaStreamer.java +++ b/src/org/kar/archidata/api/MediaStreamer.java @@ -1,8 +1,5 @@ package org.kar.archidata.api; -import jakarta.ws.rs.InternalServerErrorException; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.StreamingOutput; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; @@ -10,51 +7,55 @@ import java.io.RandomAccessFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.StreamingOutput; + public class MediaStreamer implements StreamingOutput { - static final Logger logger = LoggerFactory.getLogger(MediaStreamer.class); - private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks - final byte[] buf = new byte[CHUNK_SIZE]; - private long length; - private RandomAccessFile raf; - - public MediaStreamer(long length, RandomAccessFile raf) throws IOException { - //logger.info("request stream of {} data", length / 1024); - if (length<0) { - throw new IOException("Wrong size of the file to stream: " + length); - } - this.length = length; - this.raf = raf; - } - - @Override - public void write(OutputStream outputStream) { - try { - while (length != 0) { - int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length); - try { - outputStream.write(buf, 0, read); - } catch (IOException ex) { - logger.info("remote close connection"); - break; - } - length -= read; - } - } catch (IOException ex) { - throw new InternalServerErrorException(ex); - } catch (WebApplicationException ex) { - throw new InternalServerErrorException(ex); - } finally { - try { - raf.close(); - } catch (IOException ex) { - ex.printStackTrace(); - throw new InternalServerErrorException(ex); - } - } - } - - public long getLenth() { - return length; - } - + private static final Logger LOGGER = LoggerFactory.getLogger(MediaStreamer.class); + private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks + final byte[] buf = new byte[CHUNK_SIZE]; + private long length; + private RandomAccessFile raf; + + public MediaStreamer(long length, RandomAccessFile raf) throws IOException { + //logger.info("request stream of {} data", length / 1024); + if (length < 0) { + throw new IOException("Wrong size of the file to stream: " + length); + } + this.length = length; + this.raf = raf; + } + + @Override + public void write(OutputStream outputStream) { + try { + while (length != 0) { + int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length); + try { + outputStream.write(buf, 0, read); + } catch (IOException ex) { + LOGGER.info("remote close connection"); + break; + } + length -= read; + } + } catch (IOException ex) { + throw new InternalServerErrorException(ex); + } catch (WebApplicationException ex) { + throw new InternalServerErrorException(ex); + } finally { + try { + raf.close(); + } catch (IOException ex) { + ex.printStackTrace(); + throw new InternalServerErrorException(ex); + } + } + } + + public long getLenth() { + return length; + } + } diff --git a/src/org/kar/archidata/catcher/ExceptionCatcher.java b/src/org/kar/archidata/catcher/ExceptionCatcher.java index af08cf5..b61671d 100644 --- a/src/org/kar/archidata/catcher/ExceptionCatcher.java +++ b/src/org/kar/archidata/catcher/ExceptionCatcher.java @@ -1,29 +1,26 @@ package org.kar.archidata.catcher; -import jakarta.ws.rs.core.MediaType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; - -public class ExceptionCatcher -implements ExceptionMapper { - final Logger logger = LoggerFactory.getLogger(ExceptionCatcher.class); - @Override - public Response toResponse(Exception exception) { - logger.warn("Catch exception (not managed...):"); - RestErrorResponse ret = build(exception); - logger.error("Error UUID={}", ret.uuid); - exception.printStackTrace(); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(ret) - .type(MediaType.APPLICATION_JSON) - .build(); - } - - private RestErrorResponse build(Exception exception) { - return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch Unknown Exception", exception.getMessage()); - } - +public class ExceptionCatcher implements ExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatcher.class); + + @Override + public Response toResponse(Exception exception) { + LOGGER.warn("Catch exception (not managed...):"); + RestErrorResponse ret = build(exception); + LOGGER.error("Error UUID={}", ret.uuid); + exception.printStackTrace(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ret).type(MediaType.APPLICATION_JSON).build(); + } + + private RestErrorResponse build(Exception exception) { + return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch Unknown Exception", exception.getMessage()); + } + } diff --git a/src/org/kar/archidata/catcher/FailException404API.java b/src/org/kar/archidata/catcher/FailException404API.java index 69e6b71..f01c1a8 100644 --- a/src/org/kar/archidata/catcher/FailException404API.java +++ b/src/org/kar/archidata/catcher/FailException404API.java @@ -1,29 +1,25 @@ package org.kar.archidata.catcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import jakarta.ws.rs.ClientErrorException; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class FailException404API -implements ExceptionMapper { - final Logger logger = LoggerFactory.getLogger(FailException404API.class); - @Override - public Response toResponse(ClientErrorException exception) { - RestErrorResponse ret = build(exception); - logger.error("Error UUID={}", ret.uuid); - return Response.status(exception.getResponse().getStatusInfo().toEnum()) - .entity(ret) - .type(MediaType.APPLICATION_JSON) - .build(); - } - - private RestErrorResponse build(ClientErrorException exception) { - return new RestErrorResponse(exception.getResponse().getStatusInfo().toEnum(), "Catch system exception" , exception.getMessage()); - } - +public class FailException404API implements ExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(FailException404API.class); + + @Override + public Response toResponse(ClientErrorException exception) { + RestErrorResponse ret = build(exception); + LOGGER.error("Error UUID={}", ret.uuid); + return Response.status(exception.getResponse().getStatusInfo().toEnum()).entity(ret).type(MediaType.APPLICATION_JSON).build(); + } + + private RestErrorResponse build(ClientErrorException exception) { + return new RestErrorResponse(exception.getResponse().getStatusInfo().toEnum(), "Catch system exception", exception.getMessage()); + } + } diff --git a/src/org/kar/archidata/catcher/FailExceptionCatcher.java b/src/org/kar/archidata/catcher/FailExceptionCatcher.java index 3eac821..efa7b9e 100644 --- a/src/org/kar/archidata/catcher/FailExceptionCatcher.java +++ b/src/org/kar/archidata/catcher/FailExceptionCatcher.java @@ -1,31 +1,27 @@ package org.kar.archidata.catcher; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; - import org.kar.archidata.exception.FailException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; -public class FailExceptionCatcher -implements ExceptionMapper { - final Logger logger = LoggerFactory.getLogger(FailExceptionCatcher.class); - @Override - public Response toResponse(FailException exception) { - RestErrorResponse ret = build(exception); - logger.error("Error UUID={}", ret.uuid); - // Not display backtrace ==> this may be a normal case ... - //exception.printStackTrace(); - return Response.status(exception.status) - .entity(ret) - .type(MediaType.APPLICATION_JSON) - .build(); - } - - private RestErrorResponse build(FailException exception) { - return new RestErrorResponse(exception.status, "Request Fail", exception.getMessage()); - } - +public class FailExceptionCatcher implements ExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(FailExceptionCatcher.class); + + @Override + public Response toResponse(FailException exception) { + RestErrorResponse ret = build(exception); + LOGGER.error("Error UUID={}", ret.uuid); + // Not display backtrace ==> this may be a normal case ... + //exception.printStackTrace(); + return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build(); + } + + private RestErrorResponse build(FailException exception) { + return new RestErrorResponse(exception.status, "Request Fail", exception.getMessage()); + } + } diff --git a/src/org/kar/archidata/catcher/InputExceptionCatcher.java b/src/org/kar/archidata/catcher/InputExceptionCatcher.java index 1620cec..7029176 100644 --- a/src/org/kar/archidata/catcher/InputExceptionCatcher.java +++ b/src/org/kar/archidata/catcher/InputExceptionCatcher.java @@ -1,30 +1,26 @@ package org.kar.archidata.catcher; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; - import org.kar.archidata.exception.InputException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; -public class InputExceptionCatcher -implements ExceptionMapper { - final Logger logger = LoggerFactory.getLogger(InputExceptionCatcher.class); - @Override - public Response toResponse(InputException exception) { - RestErrorResponse ret = build(exception); - logger.error("Error UUID={}", ret.uuid); - exception.printStackTrace(); - return Response.status(exception.status) - .entity(ret) - .type(MediaType.APPLICATION_JSON) - .build(); - } - - private RestErrorResponse build(InputException exception) { - return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'" , exception.getMessage()); - } - +public class InputExceptionCatcher implements ExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(InputExceptionCatcher.class); + + @Override + public Response toResponse(InputException exception) { + RestErrorResponse ret = build(exception); + LOGGER.error("Error UUID={}", ret.uuid); + exception.printStackTrace(); + return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build(); + } + + private RestErrorResponse build(InputException exception) { + return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'", exception.getMessage()); + } + } diff --git a/src/org/kar/archidata/catcher/RestErrorResponse.java b/src/org/kar/archidata/catcher/RestErrorResponse.java index 152870e..63a2a46 100644 --- a/src/org/kar/archidata/catcher/RestErrorResponse.java +++ b/src/org/kar/archidata/catcher/RestErrorResponse.java @@ -7,7 +7,7 @@ import jakarta.ws.rs.core.Response; public class RestErrorResponse { public UUID uuid = UUID.randomUUID(); - public String time; + public String time; public String error; public String message; final public int status; @@ -20,6 +20,7 @@ public class RestErrorResponse { this.status = status.getStatusCode(); this.statusMessage = status.getReasonPhrase(); } + public RestErrorResponse(Response.Status status, String error, String message) { this.time = Instant.now().toString(); this.error = error; @@ -27,6 +28,7 @@ public class RestErrorResponse { this.status = status.getStatusCode(); this.statusMessage = status.getReasonPhrase(); } + public RestErrorResponse(Response.Status status) { this.time = Instant.now().toString(); this.status = status.getStatusCode(); diff --git a/src/org/kar/archidata/catcher/SystemExceptionCatcher.java b/src/org/kar/archidata/catcher/SystemExceptionCatcher.java index f729d26..1421683 100644 --- a/src/org/kar/archidata/catcher/SystemExceptionCatcher.java +++ b/src/org/kar/archidata/catcher/SystemExceptionCatcher.java @@ -1,30 +1,26 @@ package org.kar.archidata.catcher; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; - import org.kar.archidata.exception.SystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; -public class SystemExceptionCatcher -implements ExceptionMapper { - final Logger logger = LoggerFactory.getLogger(SystemExceptionCatcher.class); - @Override - public Response toResponse(SystemException exception) { - RestErrorResponse ret = build(exception); - logger.error("Error UUID={}", ret.uuid); - exception.printStackTrace(); - return Response.status(exception.status) - .entity(ret) - .type(MediaType.APPLICATION_JSON) - .build(); - } - - private RestErrorResponse build(SystemException exception) { - return new RestErrorResponse(exception.status, "System error", exception.getMessage()); - } - +public class SystemExceptionCatcher implements ExceptionMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(SystemExceptionCatcher.class); + + @Override + public Response toResponse(SystemException exception) { + RestErrorResponse ret = build(exception); + LOGGER.error("Error UUID={}", ret.uuid); + exception.printStackTrace(); + return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build(); + } + + private RestErrorResponse build(SystemException exception) { + return new RestErrorResponse(exception.status, "System error", exception.getMessage()); + } + } diff --git a/src/org/kar/archidata/db/DBConfig.java b/src/org/kar/archidata/db/DBConfig.java index 6733ea5..0966a84 100644 --- a/src/org/kar/archidata/db/DBConfig.java +++ b/src/org/kar/archidata/db/DBConfig.java @@ -6,87 +6,82 @@ import org.slf4j.LoggerFactory; public class DBConfig { static final Logger LOGGER = LoggerFactory.getLogger(SqlWrapper.class); - private final String type; - private final String hostname; - private final int port; - private final String login; - private final String password; - private final String dbName; - private final boolean keepConnected; - - public DBConfig(String type, String hostname, Integer port, String login, String password, String dbName, boolean keepConnected) { - if (type == null) { - this.type = "mysql"; - } else { - this.type = type; - } - if (hostname == null) { - this.hostname = "localhost"; - } else { - this.hostname = hostname; - } - if (port == null) { - this.port = 3306; - } else { - this.port = port; - } - this.login = login; - this.password = password; - this.dbName = dbName; - this.keepConnected = keepConnected; - } - - @Override - public String toString() { - return "DBConfig{" + - "type='" + type + '\'' + - ", hostname='" + hostname + '\'' + - ", port=" + port + - ", login='" + login + '\'' + - ", password='" + password + '\'' + - ", dbName='" + dbName + '\'' + - '}'; - } - - public String getHostname() { - return hostname; - } - - public int getPort() { - return port; - } - - public String getLogin() { - return login; - } - - public String getPassword() { - return password; - } - - public String getDbName() { - return dbName; - } - public boolean getKeepConnected() { - return keepConnected; - } - - public String getUrl() { - return getUrl(false); - } - public String getUrl(boolean isRoot) { - if (type.equals("sqlite")) { - if (isRoot == true) { - LOGGER.error("Can not manage root connection on SQLite..."); - } - if (this.hostname.equals("memory")) { - return "jdbc:sqlite::memory:"; - } - return "jdbc:sqlite:" + this.hostname + ".db"; - } - if (isRoot) { - return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; - } + private final String type; + private final String hostname; + private final int port; + private final String login; + private final String password; + private final String dbName; + private final boolean keepConnected; + + public DBConfig(String type, String hostname, Integer port, String login, String password, String dbName, boolean keepConnected) { + if (type == null) { + this.type = "mysql"; + } else { + this.type = type; + } + if (hostname == null) { + this.hostname = "localhost"; + } else { + this.hostname = hostname; + } + if (port == null) { + this.port = 3306; + } else { + this.port = port; + } + this.login = login; + this.password = password; + this.dbName = dbName; + this.keepConnected = keepConnected; + } + + @Override + public String toString() { + return "DBConfig{type='" + type + '\'' + ", hostname='" + hostname + '\'' + ", port=" + port + ", login='" + login + '\'' + ", password='" + password + '\'' + ", dbName='" + dbName + "' }"; + } + + public String getHostname() { + return hostname; + } + + public int getPort() { + return port; + } + + public String getLogin() { + return login; + } + + public String getPassword() { + return password; + } + + public String getDbName() { + return dbName; + } + + public boolean getKeepConnected() { + return keepConnected; + } + + public String getUrl() { + return getUrl(false); + } + + public String getUrl(boolean isRoot) { + if (type.equals("sqlite")) { + if (isRoot == true) { + LOGGER.error("Can not manage root connection on SQLite..."); + } + if (this.hostname.equals("memory")) { + return "jdbc:sqlite::memory:"; + } + return "jdbc:sqlite:" + this.hostname + ".db"; + } + if (isRoot) { + return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; + } return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/" + this.dbName + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; - } + } } diff --git a/src/org/kar/archidata/db/DBEntry.java b/src/org/kar/archidata/db/DBEntry.java index 7f2db64..1355c37 100644 --- a/src/org/kar/archidata/db/DBEntry.java +++ b/src/org/kar/archidata/db/DBEntry.java @@ -2,7 +2,9 @@ package org.kar.archidata.db; import java.io.Closeable; import java.io.IOException; -import java.sql.*; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -11,69 +13,70 @@ import org.slf4j.LoggerFactory; public class DBEntry implements Closeable { final static Logger LOGGER = LoggerFactory.getLogger(DBEntry.class); - public DBConfig config; - public Connection connection; - private static List stored = new ArrayList<>(); - - private DBEntry(DBConfig config, boolean root) throws IOException { - this.config = config; - if (root) { - connectRoot(); - } else { - connect(); - } - } - - public static DBEntry createInterface(DBConfig config) throws IOException { - return createInterface(config, false); - } - public static DBEntry createInterface(DBConfig config, boolean root) throws IOException { - if (config.getKeepConnected()) { - for (DBEntry elem : stored) { - if (elem == null) { - continue; - } - if (elem.config.getUrl().equals(config.getUrl())) { - return elem; - } - } - DBEntry tmp = new DBEntry(config, root); - stored.add(tmp); - return tmp; - } else { - return new DBEntry(config, root); - } - } - - public void connectRoot() throws IOException { - try { - connection = DriverManager.getConnection(config.getUrl(true), config.getLogin(), config.getPassword()); - } catch (SQLException ex) { - throw new IOException("Connection db fail: " + ex.getMessage()); - } - - } - - public void connect() throws IOException { - try { - connection = DriverManager.getConnection(config.getUrl(), config.getLogin(), config.getPassword()); - } catch (SQLException ex) { - throw new IOException("Connection db fail: " + ex.getMessage()); - } - - } - + public DBConfig config; + public Connection connection; + private static List stored = new ArrayList<>(); + + private DBEntry(DBConfig config, boolean root) throws IOException { + this.config = config; + if (root) { + connectRoot(); + } else { + connect(); + } + } + + public static DBEntry createInterface(DBConfig config) throws IOException { + return createInterface(config, false); + } + + public static DBEntry createInterface(DBConfig config, boolean root) throws IOException { + if (config.getKeepConnected()) { + for (DBEntry elem : stored) { + if (elem == null) { + continue; + } + if (elem.config.getUrl().equals(config.getUrl())) { + return elem; + } + } + DBEntry tmp = new DBEntry(config, root); + stored.add(tmp); + return tmp; + } else { + return new DBEntry(config, root); + } + } + + public void connectRoot() throws IOException { + try { + connection = DriverManager.getConnection(config.getUrl(true), config.getLogin(), config.getPassword()); + } catch (SQLException ex) { + throw new IOException("Connection db fail: " + ex.getMessage()); + } + + } + + public void connect() throws IOException { + try { + connection = DriverManager.getConnection(config.getUrl(), config.getLogin(), config.getPassword()); + } catch (SQLException ex) { + throw new IOException("Connection db fail: " + ex.getMessage()); + } + + } + @Override public void close() throws IOException { if (config.getKeepConnected()) { return; } - try { - //connection.commit(); - connection.close(); - } catch (SQLException ex) { - throw new IOException("Dis-connection db fail: " + ex.getMessage()); - } + try { + //connection.commit(); + connection.close(); + } catch (SQLException ex) { + throw new IOException("Dis-connection db fail: " + ex.getMessage()); + } } } diff --git a/src/org/kar/archidata/exception/FailException.java b/src/org/kar/archidata/exception/FailException.java index 1f0e8ab..7b58416 100644 --- a/src/org/kar/archidata/exception/FailException.java +++ b/src/org/kar/archidata/exception/FailException.java @@ -5,10 +5,12 @@ import jakarta.ws.rs.core.Response; public class FailException extends Exception { private static final long serialVersionUID = 1L; public final Response.Status status; + public FailException(Response.Status status, String message) { super(message); this.status = status; } + public FailException(String message) { super(message); this.status = Response.Status.BAD_REQUEST; diff --git a/src/org/kar/archidata/exception/InputException.java b/src/org/kar/archidata/exception/InputException.java index 1c4b69a..1a3a610 100644 --- a/src/org/kar/archidata/exception/InputException.java +++ b/src/org/kar/archidata/exception/InputException.java @@ -6,11 +6,13 @@ public class InputException extends Exception { private static final long serialVersionUID = 1L; public final String missingVariable; public final Response.Status status; + public InputException(Response.Status status, String variable, String message) { super(message); this.missingVariable = variable; this.status = status; } + public InputException(String variable, String message) { super(message); this.missingVariable = variable; diff --git a/src/org/kar/archidata/exception/NotFoundException.java b/src/org/kar/archidata/exception/NotFoundException.java index ed5df9a..d2e5fdb 100644 --- a/src/org/kar/archidata/exception/NotFoundException.java +++ b/src/org/kar/archidata/exception/NotFoundException.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.core.Response; public class NotFoundException extends FailException { private static final long serialVersionUID = 1L; + public NotFoundException(String message) { super(Response.Status.NOT_FOUND, message); } diff --git a/src/org/kar/archidata/exception/RESTErrorResponseExeption.java b/src/org/kar/archidata/exception/RESTErrorResponseExeption.java index ed0870a..fb52729 100644 --- a/src/org/kar/archidata/exception/RESTErrorResponseExeption.java +++ b/src/org/kar/archidata/exception/RESTErrorResponseExeption.java @@ -4,12 +4,12 @@ import java.util.UUID; public class RESTErrorResponseExeption extends Exception { public UUID uuid; - public String time; + public String time; public String error; public String message; public int status; public String statusMessage; - + public RESTErrorResponseExeption() { super(); this.uuid = null; @@ -19,8 +19,8 @@ public class RESTErrorResponseExeption extends Exception { this.status = 0; this.statusMessage = null; } - public RESTErrorResponseExeption(UUID uuid, String time, String error, String message, int status, - String statusMessage) { + + public RESTErrorResponseExeption(UUID uuid, String time, String error, String message, int status, String statusMessage) { super(); this.uuid = uuid; this.time = time; @@ -29,13 +29,10 @@ public class RESTErrorResponseExeption extends Exception { this.status = status; this.statusMessage = statusMessage; } - + @Override public String toString() { - return "RESTErrorResponseExeption [uuid=" + uuid + ", time=" + time + ", error=" + error + ", message=" - + message + ", status=" + status + ", statusMessage=" + statusMessage + "]"; + return "RESTErrorResponseExeption [uuid=" + uuid + ", time=" + time + ", error=" + error + ", message=" + message + ", status=" + status + ", statusMessage=" + statusMessage + "]"; } - - } diff --git a/src/org/kar/archidata/exception/SystemException.java b/src/org/kar/archidata/exception/SystemException.java index d5fe003..70e91bb 100644 --- a/src/org/kar/archidata/exception/SystemException.java +++ b/src/org/kar/archidata/exception/SystemException.java @@ -5,10 +5,12 @@ import jakarta.ws.rs.core.Response; public class SystemException extends Exception { private static final long serialVersionUID = 1L; public final Response.Status status; + public SystemException(Response.Status status, String message) { super(message); this.status = status; } + public SystemException(String message) { super(message); this.status = Response.Status.INTERNAL_SERVER_ERROR; diff --git a/src/org/kar/archidata/exception/UnAuthorizedException.java b/src/org/kar/archidata/exception/UnAuthorizedException.java index 731f277..54085b9 100644 --- a/src/org/kar/archidata/exception/UnAuthorizedException.java +++ b/src/org/kar/archidata/exception/UnAuthorizedException.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.core.Response; public class UnAuthorizedException extends FailException { private static final long serialVersionUID = 1L; + public UnAuthorizedException(String message) { super(Response.Status.UNAUTHORIZED, message); } diff --git a/src/org/kar/archidata/filter/AuthenticationFilter.java b/src/org/kar/archidata/filter/AuthenticationFilter.java index e17de8b..3ad8231 100644 --- a/src/org/kar/archidata/filter/AuthenticationFilter.java +++ b/src/org/kar/archidata/filter/AuthenticationFilter.java @@ -1,10 +1,26 @@ package org.kar.archidata.filter; +import java.io.IOException; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey +// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey/45814178#45814178 +// https://stackoverflow.com/questions/32817210/how-to-access-jersey-resource-secured-by-rolesallowed + import org.kar.archidata.annotation.security.DenyAll; import org.kar.archidata.annotation.security.PermitAll; +import org.kar.archidata.annotation.security.PermitTokenInURI; import org.kar.archidata.annotation.security.RolesAllowed; import org.kar.archidata.catcher.RestErrorResponse; +import org.kar.archidata.model.UserByToken; +import org.kar.archidata.util.JWTWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.nimbusds.jwt.JWTClaimsSet; import jakarta.annotation.Priority; import jakarta.ws.rs.Priorities; @@ -18,23 +34,6 @@ import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; -import org.kar.archidata.annotation.security.PermitTokenInURI; -import org.kar.archidata.model.UserByToken; -import org.kar.archidata.util.JWTWrapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.nimbusds.jwt.JWTClaimsSet; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey -// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey/45814178#45814178 -// https://stackoverflow.com/questions/32817210/how-to-access-jersey-resource-secured-by-rolesallowed - //@PreMatching @Provider @Priority(Priorities.AUTHENTICATION) @@ -43,189 +42,183 @@ public class AuthenticationFilter implements ContainerRequestFilter { @Context private ResourceInfo resourceInfo; protected final String applicationName; - - private static final String AUTHENTICATION_SCHEME = "Yota"; - private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota"; - - - - public AuthenticationFilter(String applicationName) { + + private static final String AUTHENTICATION_SCHEME = "Yota"; + private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota"; + + public AuthenticationFilter(String applicationName) { super(); this.applicationName = applicationName; } - + @Override - public void filter(ContainerRequestContext requestContext) throws IOException { - /* - logger.debug("-----------------------------------------------------"); - logger.debug("---- Check if have authorization ----"); - logger.debug("-----------------------------------------------------"); - logger.debug(" for:{}", requestContext.getUriInfo().getPath()); - */ - Method method = resourceInfo.getResourceMethod(); - // Access denied for all - if(method.isAnnotationPresent(DenyAll.class)) { - logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath()); - requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build()); - return; - } - - //Access allowed for all - if( method.isAnnotationPresent(PermitAll.class)) { - //logger.debug(" ==> permit all " + requestContext.getUriInfo().getPath()); - // no control ... - return; - } - // this is a security guard, all the API must define their access level: - if(!method.isAnnotationPresent(RolesAllowed.class)) { - logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath()); - requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build()); - return; - } - - // Get the Authorization header from the request - String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); - //logger.debug("authorizationHeader: {}", authorizationHeader); - if(authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) { - MultivaluedMap quaryparam = requestContext.getUriInfo().getQueryParameters(); - for (Entry> item: quaryparam.entrySet()) { - if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) { - if (!item.getValue().isEmpty()) { - authorizationHeader = item.getValue().get(0); - } - break; - } - } - } - // logger.debug("authorizationHeader: {}", authorizationHeader); - boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader); - boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader); - // Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)" - if (!isApplicationToken && !isJwtToken) { - logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath()); - abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath()); - return; - } - UserByToken userByToken = null; - if (isJwtToken) { - // Extract the token from the Authorization header (Remove "Yota ") - String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim(); - //logger.debug("token: {}", token); - try { - userByToken = validateJwtToken(token); - } catch (Exception e) { - logger.error("Fail to validate token: {}", e.getMessage()); - abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage()); - return; - } - if (userByToken == null) { - logger.warn("get a NULL user ..."); - abortWithUnauthorized(requestContext, "get a NULL user ..."); - return; - } - } else { - // Extract the token from the Authorization header (Remove "Zota ") - String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim(); - //logger.debug("token: {}", token); - try { - userByToken = validateToken(token); - } catch (Exception e) { - logger.error("Fail to validate token: {}", e.getMessage()); - abortWithUnauthorized(requestContext, "Fail to validate token: "+ e.getMessage()); - return; - } - if (userByToken == null) { - logger.warn("get a NULL application ..."); - abortWithUnauthorized(requestContext, "get a NULL application ..."); - return; - } - - } - // create the security context model: - String scheme = requestContext.getUriInfo().getRequestUri().getScheme(); - MySecurityContext userContext = new MySecurityContext(userByToken, scheme); - // retrieve the allowed right: - RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); - List roles = Arrays.asList(rolesAnnotation.value()); - // check if the user have the right: - boolean haveRight = false; - for (String role : roles) { - if (userContext.isUserInRole(role)) { - haveRight = true; - break; - } - } - //Is user valid? - if( ! haveRight) { - logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles); - requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build()); - return; - } - requestContext.setSecurityContext(userContext); - // logger.debug("Get local user : {} / {}", user, userByToken); - } - - private boolean isTokenBasedAuthentication(String authorizationHeader) { - // Check if the Authorization header is valid - // It must not be null and must be prefixed with "Bearer" plus a whitespace - // The authentication scheme comparison must be case-insensitive - return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " "); - } - - private boolean isApplicationTokenBasedAuthentication(String authorizationHeader) { - // Check if the Authorization header is valid - // It must not be null and must be prefixed with "Bearer" plus a whitespace - // The authentication scheme comparison must be case-insensitive - return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " "); - } - - - private void abortWithUnauthorized(ContainerRequestContext requestContext, String message) { - - // Abort the filter chain with a 401 status code response - // The WWW-Authenticate header is sent along with the response - logger.warn("abortWithUnauthorized:"); + public void filter(ContainerRequestContext requestContext) throws IOException { + /* + logger.debug("-----------------------------------------------------"); + logger.debug("---- Check if have authorization ----"); + logger.debug("-----------------------------------------------------"); + logger.debug(" for:{}", requestContext.getUriInfo().getPath()); + */ + Method method = resourceInfo.getResourceMethod(); + // Access denied for all + if (method.isAnnotationPresent(DenyAll.class)) { + logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build()); + return; + } + + //Access allowed for all + if (method.isAnnotationPresent(PermitAll.class)) { + //logger.debug(" ==> permit all " + requestContext.getUriInfo().getPath()); + // no control ... + return; + } + // this is a security guard, all the API must define their access level: + if (!method.isAnnotationPresent(RolesAllowed.class)) { + logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build()); + return; + } + + // Get the Authorization header from the request + String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); + //logger.debug("authorizationHeader: {}", authorizationHeader); + if (authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) { + MultivaluedMap quaryparam = requestContext.getUriInfo().getQueryParameters(); + for (Entry> item : quaryparam.entrySet()) { + if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) { + if (!item.getValue().isEmpty()) { + authorizationHeader = item.getValue().get(0); + } + break; + } + } + } + // logger.debug("authorizationHeader: {}", authorizationHeader); + boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader); + boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader); + // Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)" + if (!isApplicationToken && !isJwtToken) { + logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath()); + abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath()); + return; + } + UserByToken userByToken = null; + if (isJwtToken) { + // Extract the token from the Authorization header (Remove "Yota ") + String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim(); + //logger.debug("token: {}", token); + try { + userByToken = validateJwtToken(token); + } catch (Exception e) { + logger.error("Fail to validate token: {}", e.getMessage()); + abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage()); + return; + } + if (userByToken == null) { + logger.warn("get a NULL user ..."); + abortWithUnauthorized(requestContext, "get a NULL user ..."); + return; + } + } else { + // Extract the token from the Authorization header (Remove "Zota ") + String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim(); + //logger.debug("token: {}", token); + try { + userByToken = validateToken(token); + } catch (Exception e) { + logger.error("Fail to validate token: {}", e.getMessage()); + abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage()); + return; + } + if (userByToken == null) { + logger.warn("get a NULL application ..."); + abortWithUnauthorized(requestContext, "get a NULL application ..."); + return; + } + + } + // create the security context model: + String scheme = requestContext.getUriInfo().getRequestUri().getScheme(); + MySecurityContext userContext = new MySecurityContext(userByToken, scheme); + // retrieve the allowed right: + RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); + List roles = Arrays.asList(rolesAnnotation.value()); + // check if the user have the right: + boolean haveRight = false; + for (String role : roles) { + if (userContext.isUserInRole(role)) { + haveRight = true; + break; + } + } + //Is user valid? + if (!haveRight) { + logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles); + requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build()); + return; + } + requestContext.setSecurityContext(userContext); + // logger.debug("Get local user : {} / {}", user, userByToken); + } + + private boolean isTokenBasedAuthentication(String authorizationHeader) { + // Check if the Authorization header is valid + // It must not be null and must be prefixed with "Bearer" plus a whitespace + // The authentication scheme comparison must be case-insensitive + return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " "); + } + + private boolean isApplicationTokenBasedAuthentication(String authorizationHeader) { + // Check if the Authorization header is valid + // It must not be null and must be prefixed with "Bearer" plus a whitespace + // The authentication scheme comparison must be case-insensitive + return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " "); + } + + private void abortWithUnauthorized(ContainerRequestContext requestContext, String message) { + + // Abort the filter chain with a 401 status code response + // The WWW-Authenticate header is sent along with the response + logger.warn("abortWithUnauthorized:"); RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message); logger.error("Error UUID={}", ret.uuid); - requestContext.abortWith(Response.status(ret.status) - .header(HttpHeaders.WWW_AUTHENTICATE, - AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)") - .entity(ret) - .type(MediaType.APPLICATION_JSON) - .build()); - } - - protected UserByToken validateToken(String authorization) throws Exception { - logger.info("Must be Override by the application implmentation, otherwise it dose not work"); - return null; - } - // must be override to be good implementation - protected UserByToken validateJwtToken(String authorization) throws Exception { - //logger.debug(" validate token : " + authorization); - JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null); - // check the token is valid !!! (signed and coherent issuer... - if (ret == null) { - logger.error("The token is not valid: '{}'", authorization); - return null; - } - // check userID - String userUID = ret.getSubject(); - long id = Long.parseLong(userUID); - UserByToken user = new UserByToken(); - user.id = id; - user.name = (String)ret.getClaim("login"); - user.type = UserByToken.TYPE_USER; - Object rowRight = ret.getClaim("right"); - if (rowRight != null) { - Map> rights = (Map>) ret.getClaim("right"); - if (rights.containsKey(this.applicationName)) { - user.right = rights.get(this.applicationName); - } else { - logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights); - } - } - //logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight); - return user; - //return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") ); - } + requestContext.abortWith(Response.status(ret.status).header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)").entity(ret) + .type(MediaType.APPLICATION_JSON).build()); + } + + protected UserByToken validateToken(String authorization) throws Exception { + logger.info("Must be Override by the application implmentation, otherwise it dose not work"); + return null; + } + + // must be override to be good implementation + protected UserByToken validateJwtToken(String authorization) throws Exception { + //logger.debug(" validate token : " + authorization); + JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null); + // check the token is valid !!! (signed and coherent issuer... + if (ret == null) { + logger.error("The token is not valid: '{}'", authorization); + return null; + } + // check userID + String userUID = ret.getSubject(); + long id = Long.parseLong(userUID); + UserByToken user = new UserByToken(); + user.id = id; + user.name = (String) ret.getClaim("login"); + user.type = UserByToken.TYPE_USER; + Object rowRight = ret.getClaim("right"); + if (rowRight != null) { + Map> rights = (Map>) ret.getClaim("right"); + if (rights.containsKey(this.applicationName)) { + user.right = rights.get(this.applicationName); + } else { + logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights); + } + } + //logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight); + return user; + //return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") ); + } } diff --git a/src/org/kar/archidata/filter/CORSFilter.java b/src/org/kar/archidata/filter/CORSFilter.java index 9046e6d..6675bc9 100644 --- a/src/org/kar/archidata/filter/CORSFilter.java +++ b/src/org/kar/archidata/filter/CORSFilter.java @@ -1,25 +1,23 @@ package org.kar.archidata.filter; +import java.io.IOException; + import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerResponseContext; import jakarta.ws.rs.container.ContainerResponseFilter; import jakarta.ws.rs.ext.Provider; -import java.io.IOException; - @Provider public class CORSFilter implements ContainerResponseFilter { - - @Override - public void filter(ContainerRequestContext request, - ContainerResponseContext response) throws IOException { - //System.err.println("filter cors ..." + request.toString()); - - response.getHeaders().add("Access-Control-Allow-Origin", "*"); - response.getHeaders().add("Access-Control-Allow-Headers", "*"); - // "Origin, content-type, Content-type, Accept, authorization, mime-type, filename"); - response.getHeaders().add("Access-Control-Allow-Credentials", "true"); - response.getHeaders().add("Access-Control-Allow-Methods", - "GET, POST, PUT, DELETE, OPTIONS, HEAD"); - } + + @Override + public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { + //System.err.println("filter cors ..." + request.toString()); + + response.getHeaders().add("Access-Control-Allow-Origin", "*"); + response.getHeaders().add("Access-Control-Allow-Headers", "*"); + // "Origin, content-type, Content-type, Accept, authorization, mime-type, filename"); + response.getHeaders().add("Access-Control-Allow-Credentials", "true"); + response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); + } } diff --git a/src/org/kar/archidata/filter/GenericContext.java b/src/org/kar/archidata/filter/GenericContext.java index b7a177f..4fbaa2e 100644 --- a/src/org/kar/archidata/filter/GenericContext.java +++ b/src/org/kar/archidata/filter/GenericContext.java @@ -1,22 +1,22 @@ package org.kar.archidata.filter; -import org.kar.archidata.model.UserByToken; - import java.security.Principal; +import org.kar.archidata.model.UserByToken; + public class GenericContext implements Principal { - - public UserByToken userByToken; - - public GenericContext(UserByToken userByToken) { - this.userByToken = userByToken; - } - - @Override - public String getName() { - if (this.userByToken == null) { - return "???"; - } - return this.userByToken.name; - } + + public UserByToken userByToken; + + public GenericContext(UserByToken userByToken) { + this.userByToken = userByToken; + } + + @Override + public String getName() { + if (this.userByToken == null) { + return "???"; + } + return this.userByToken.name; + } } diff --git a/src/org/kar/archidata/filter/MySecurityContext.java b/src/org/kar/archidata/filter/MySecurityContext.java index a5e442e..a66453c 100644 --- a/src/org/kar/archidata/filter/MySecurityContext.java +++ b/src/org/kar/archidata/filter/MySecurityContext.java @@ -1,48 +1,49 @@ package org.kar.archidata.filter; +import java.security.Principal; + import org.kar.archidata.model.UserByToken; import jakarta.ws.rs.core.SecurityContext; -import java.security.Principal; // https://simplapi.wordpress.com/2015/09/19/jersey-jax-rs-securitycontext-in-action/ class MySecurityContext implements SecurityContext { - - private final GenericContext contextPrincipale; - private final String sheme; - - public MySecurityContext(UserByToken userByToken, String sheme) { - this.contextPrincipale = new GenericContext(userByToken); - this.sheme = sheme; - } - - @Override - public Principal getUserPrincipal() { - return contextPrincipale; - } - - @Override - public boolean isUserInRole(String role) { - if (contextPrincipale.userByToken != null) { - Object value = this.contextPrincipale.userByToken.right.get(role); - if (value instanceof Boolean ret) { - return ret; - } - } - return false; - } - - @Override - public boolean isSecure() { - return sheme.equalsIgnoreCase("https"); - } - - @Override - public String getAuthenticationScheme() { - if (contextPrincipale.userByToken != null) { - return "Zota"; - } - return null; - } - + + private final GenericContext contextPrincipale; + private final String sheme; + + public MySecurityContext(UserByToken userByToken, String sheme) { + this.contextPrincipale = new GenericContext(userByToken); + this.sheme = sheme; + } + + @Override + public Principal getUserPrincipal() { + return contextPrincipale; + } + + @Override + public boolean isUserInRole(String role) { + if (contextPrincipale.userByToken != null) { + Object value = this.contextPrincipale.userByToken.right.get(role); + if (value instanceof Boolean ret) { + return ret; + } + } + return false; + } + + @Override + public boolean isSecure() { + return sheme.equalsIgnoreCase("https"); + } + + @Override + public String getAuthenticationScheme() { + if (contextPrincipale.userByToken != null) { + return "Zota"; + } + return null; + } + } \ No newline at end of file diff --git a/src/org/kar/archidata/filter/OptionFilter.java b/src/org/kar/archidata/filter/OptionFilter.java index a1282d3..cff309a 100644 --- a/src/org/kar/archidata/filter/OptionFilter.java +++ b/src/org/kar/archidata/filter/OptionFilter.java @@ -1,21 +1,20 @@ package org.kar.archidata.filter; +import java.io.IOException; + import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.container.PreMatching; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; -import java.io.IOException; @Provider @PreMatching public class OptionFilter implements ContainerRequestFilter { - @Override - public void filter(ContainerRequestContext requestContext) throws IOException { - if (requestContext.getMethod().contentEquals("OPTIONS")) { - requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build()); - } - } + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + if (requestContext.getMethod().contentEquals("OPTIONS")) { + requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build()); + } + } } - - diff --git a/src/org/kar/archidata/migration/MigrationEngine.java b/src/org/kar/archidata/migration/MigrationEngine.java index 62736b6..41e024b 100644 --- a/src/org/kar/archidata/migration/MigrationEngine.java +++ b/src/org/kar/archidata/migration/MigrationEngine.java @@ -25,15 +25,17 @@ public class MigrationEngine { public MigrationEngine() { this(new ArrayList(), null); } + /** * Migration engine constructor (specific mode). * @param datas All the migration ordered. * @param init Initialization migration model. */ - public MigrationEngine( List datas, MigrationInterface init) { + public MigrationEngine(List datas, MigrationInterface init) { this.datas = datas; this.init = init; } + /** * Add a Migration in the list * @param migration Migration to add. @@ -41,6 +43,7 @@ public class MigrationEngine { public void add(MigrationInterface migration) { this.datas.add(migration); } + /** * Set first initialization class * @param migration migration class for first init. @@ -48,6 +51,7 @@ public class MigrationEngine { public void setInit(MigrationInterface migration) { init = migration; } + /** * Get the current version/migration name * @return Model represent the last migration. If null then no migration has been done. @@ -59,7 +63,7 @@ public class MigrationEngine { try { List data = SqlWrapper.gets(MigrationModel.class, false); if (data == null) { - LOGGER.error("Can not collect the migration table in the DB:{}" ); + LOGGER.error("Can not collect the migration table in the DB:{}"); return null; } if (data.size() == 0) { @@ -68,15 +72,16 @@ public class MigrationEngine { } LOGGER.debug("List of migrations:"); for (MigrationModel elem : data) { - LOGGER.debug(" - date={} name={} end={}", elem.modify_date, elem.name, elem.terminated); + LOGGER.debug(" - date={} name={} end={}", elem.modify_date, elem.name, elem.terminated); } - return data.get(data.size()-1); + return data.get(data.size() - 1); } catch (Exception ex) { LOGGER.error("Fail to Request migration table in the DB:{}", ex.getMessage()); ex.printStackTrace(); } return null; } + /** * Process the automatic migration of the system * @param config SQL connection for the migration @@ -85,11 +90,11 @@ public class MigrationEngine { */ public void migrate(DBConfig config) throws InterruptedException, IOException { LOGGER.info("Execute migration ... [BEGIN]"); - + // STEP 1: Check the DB exist: LOGGER.info("Verify existance of '{}'", config.getDbName()); boolean exist = SqlWrapper.isDBExist(config.getDbName()); - if(!exist) { + if (!exist) { LOGGER.warn("DB: '{}' DOES NOT EXIST ==> create one", config.getDbName()); // create the local DB: SqlWrapper.createDB(config.getDbName()); @@ -114,7 +119,7 @@ public class MigrationEngine { ex.printStackTrace(); while (true) { LOGGER.error("Fail to create the local DB SQL model for migaration ==> wait administrator interventions"); - Thread.sleep(60*60*1000); + Thread.sleep(60 * 60 * 1000); } } LOGGER.info("Create Table with : {}", sqlQuery.get(0)); @@ -124,7 +129,7 @@ public class MigrationEngine { ex.printStackTrace(); while (true) { LOGGER.error("Fail to create the local DB model for migaration ==> wait administrator interventions"); - Thread.sleep(60*60*1000); + Thread.sleep(60 * 60 * 1000); } } } @@ -142,15 +147,15 @@ public class MigrationEngine { // nothing to do the initialization model is alone and it is the first time } else { // we insert a placeholder to simulate all migration is well done. - String placeholderName = this.datas.get(this.datas.size()-1).getName(); + String placeholderName = this.datas.get(this.datas.size() - 1).getName(); MigrationModel migrationResult = new MigrationModel(); - migrationResult.name = placeholderName; + migrationResult.name = placeholderName; migrationResult.stepId = 0; migrationResult.terminated = true; - migrationResult.count = 0; - migrationResult.log = "Place-holder for first initialization"; - try { - migrationResult = SqlWrapper.insert(migrationResult); + migrationResult.count = 0; + migrationResult.log = "Place-holder for first initialization"; + try { + migrationResult = SqlWrapper.insert(migrationResult); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -158,9 +163,9 @@ public class MigrationEngine { } } else { if (currentVersion.terminated == false) { - while(true) { - LOGGER.error("An error occured in the last migration: '{}' defect @{}/{} ==> wait administrator interventions", currentVersion.name , currentVersion.stepId, currentVersion.count); - Thread.sleep(60*60*1000); + while (true) { + LOGGER.error("An error occured in the last migration: '{}' defect @{}/{} ==> wait administrator interventions", currentVersion.name, currentVersion.stepId, currentVersion.count); + Thread.sleep(60 * 60 * 1000); } } LOGGER.info("Upgrade the system Current version: {}", currentVersion.name); @@ -168,8 +173,8 @@ public class MigrationEngine { if (currentVersion.name.equals(this.init.getName())) { toApply = this.datas; } else { - for (int iii=0; iii wait administrator interventions", migrationResult.name , migrationResult.stepId, migrationResult.count); + while (true) { + LOGGER.error("An error occured in the migration (OUTSIDE detection): '{}' defect @{}/{} ==> wait administrator interventions", migrationResult.name, migrationResult.stepId, + migrationResult.count); try { - Thread.sleep(60*60*1000); + Thread.sleep(60 * 60 * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -231,13 +238,13 @@ public class MigrationEngine { } LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName()); } - + public void revertTo(DBEntry entry, String migrationName) { MigrationModel currentVersion = getCurrentVersion(); List toApply = new ArrayList<>(); boolean find = false; - for (int iii=this.datas.size()-1; iii>=0; iii--) { - if ( ! find) { + for (int iii = this.datas.size() - 1; iii >= 0; iii--) { + if (!find) { if (this.datas.get(iii).getName() == currentVersion.name) { find = true; } @@ -254,6 +261,7 @@ public class MigrationEngine { revertSingle(entry, elem, id, count); } } + public void revertSingle(DBEntry entry, MigrationInterface elem, int id, int count) { LOGGER.info("Revert migration: {} [BEGIN]", elem.getName()); diff --git a/src/org/kar/archidata/migration/MigrationException.java b/src/org/kar/archidata/migration/MigrationException.java index 80afc2c..55c24a3 100644 --- a/src/org/kar/archidata/migration/MigrationException.java +++ b/src/org/kar/archidata/migration/MigrationException.java @@ -1,7 +1,7 @@ package org.kar.archidata.migration; public class MigrationException extends Exception { - + private static final long serialVersionUID = 20230502L; } diff --git a/src/org/kar/archidata/migration/MigrationInterface.java b/src/org/kar/archidata/migration/MigrationInterface.java index cf2a561..f0100fa 100644 --- a/src/org/kar/archidata/migration/MigrationInterface.java +++ b/src/org/kar/archidata/migration/MigrationInterface.java @@ -8,6 +8,7 @@ public interface MigrationInterface { * @return Migration name */ String getName(); + /** * Migrate the system to a new version. * @param entry DB interface for the migration. @@ -16,6 +17,7 @@ public interface MigrationInterface { * @return true if migration is finished. */ boolean applyMigration(DBEntry entry, StringBuilder log, MigrationModel model); + /** * Remove a migration the system to the previous version. * @param entry DB interface for the migration. diff --git a/src/org/kar/archidata/migration/MigrationModel.java b/src/org/kar/archidata/migration/MigrationModel.java index bb2fbaa..999b6de 100644 --- a/src/org/kar/archidata/migration/MigrationModel.java +++ b/src/org/kar/archidata/migration/MigrationModel.java @@ -3,31 +3,31 @@ package org.kar.archidata.migration; import org.kar.archidata.annotation.SQLComment; import org.kar.archidata.annotation.SQLDefault; import org.kar.archidata.annotation.SQLIfNotExists; -import org.kar.archidata.annotation.SQLLimitSize; -import org.kar.archidata.annotation.SQLNotNull; -import org.kar.archidata.annotation.SQLTableName; import org.kar.archidata.model.GenericTable; import com.fasterxml.jackson.annotation.JsonInclude; +import jakarta.persistence.Column; +import jakarta.persistence.Table; + // For logs only //public static final String TABLE_NAME = "KAR_migration"; -@SQLTableName ("KAR_migration") +@Table(name = "KAR_migration") @SQLIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) -public class MigrationModel extends GenericTable{ +public class MigrationModel extends GenericTable { @SQLComment("Name of the migration") - @SQLLimitSize(256) - public String name; - @SQLNotNull + @Column(length = 256) + public String name; + @Column(nullable = false) @SQLDefault("'0'") - @SQLComment("if the migration is well terminated or not") - public Boolean terminated = false; - @SQLComment("index in the migration progression") - public Integer stepId = 0; - @SQLComment("number of element in the migration") - public Integer count; - @SQLComment("Log generate by the migration") - public String log = ""; + @SQLComment("if the migration is well terminated or not") + public Boolean terminated = false; + @SQLComment("index in the migration progression") + public Integer stepId = 0; + @SQLComment("number of element in the migration") + public Integer count; + @SQLComment("Log generate by the migration") + public String log = ""; } diff --git a/src/org/kar/archidata/migration/MigrationSqlStep.java b/src/org/kar/archidata/migration/MigrationSqlStep.java index d3b956f..cd34cb3 100644 --- a/src/org/kar/archidata/migration/MigrationSqlStep.java +++ b/src/org/kar/archidata/migration/MigrationSqlStep.java @@ -12,19 +12,26 @@ import org.slf4j.LoggerFactory; public class MigrationSqlStep implements MigrationInterface { final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class); - private List actions = new ArrayList<>(); - + private final List actions = new ArrayList<>(); + @Override public String getName() { return getClass().getCanonicalName(); } + public void display() { + for (int iii = 0; iii < this.actions.size(); iii++) { + final String action = this.actions.get(iii); + LOGGER.info(" >>>> SQL ACTION : {}/{} ==> \n{}", iii, this.actions.size(), action); + } + } + @Override - public boolean applyMigration(DBEntry entry, StringBuilder log, MigrationModel model) { - for (int iii=0; iii>>> SQL ACTION : {}/{}", iii, actions.size()); - String action = actions.get(iii); + public boolean applyMigration(final DBEntry entry, final StringBuilder log, final MigrationModel model) { + for (int iii = 0; iii < this.actions.size(); iii++) { + log.append("action [" + iii + "/" + this.actions.size() + "]\n"); + LOGGER.info(" >>>> SQL ACTION : {}/{}", iii, this.actions.size()); + final String action = this.actions.get(iii); LOGGER.info("SQL request: ```{}```", action); log.append("SQL: " + action + "\n"); try { @@ -33,28 +40,28 @@ public class MigrationSqlStep implements MigrationInterface { ex.printStackTrace(); LOGGER.info("SQL request ERROR: ", ex.getMessage()); log.append("SQL request ERROR: " + ex.getMessage() + "\n"); - model.stepId = iii+1; + model.stepId = iii + 1; model.log = log.toString(); - try { - SqlWrapper.update(model, model.id, List.of("stepId", "log")); - } catch (Exception e) { + try { + SqlWrapper.update(model, model.id, List.of("stepId", "log")); + } catch (final Exception e) { e.printStackTrace(); } return false; } - log.append("action [" + iii + "/" + actions.size() + "] ==> DONE\n"); - LOGGER.info(" >>>> SQL ACTION : {}/{} ==> DONE", iii, actions.size()); - model.stepId = iii+1; + log.append("action [" + iii + "/" + this.actions.size() + "] ==> DONE\n"); + LOGGER.info(" >>>> SQL ACTION : {}/{} ==> DONE", iii, this.actions.size()); + model.stepId = iii + 1; model.log = log.toString(); - try { - SqlWrapper.update(model, model.id, List.of("stepId", "log")); - } catch (Exception e) { + try { + SqlWrapper.update(model, model.id, List.of("stepId", "log")); + } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - try { + try { Thread.sleep(100); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } @@ -63,21 +70,22 @@ public class MigrationSqlStep implements MigrationInterface { } @Override - public boolean revertMigration(DBEntry entry, StringBuilder log) { + public boolean revertMigration(final DBEntry entry, final StringBuilder log) { return false; } - public void addAction(String action) { - actions.add(action); + public void addAction(final String action) { + this.actions.add(action); } - public void addClass(Class clazz) throws Exception { - List tmp = SqlWrapper.createTable(clazz, false); - actions.addAll(tmp); + + public void addClass(final Class clazz) throws Exception { + final List tmp = SqlWrapper.createTable(clazz, false); + this.actions.addAll(tmp); } @Override public int getNumberOfStep() { - return actions.size(); + return this.actions.size(); } } diff --git a/src/org/kar/archidata/model/Data.java b/src/org/kar/archidata/model/Data.java index a63502f..2bef3b7 100644 --- a/src/org/kar/archidata/model/Data.java +++ b/src/org/kar/archidata/model/Data.java @@ -1,28 +1,25 @@ package org.kar.archidata.model; - import org.kar.archidata.annotation.SQLComment; import org.kar.archidata.annotation.SQLIfNotExists; -import org.kar.archidata.annotation.SQLLimitSize; -import org.kar.archidata.annotation.SQLNotNull; -import org.kar.archidata.annotation.SQLTableName; import com.fasterxml.jackson.annotation.JsonInclude; -@SQLTableName ("data") +import jakarta.persistence.Column; +import jakarta.persistence.Table; + +@Table(name = "data") @SQLIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Data extends GenericTable { - @SQLNotNull - @SQLLimitSize(128) - @SQLComment("Sha512 of the data") - public String sha512; - @SQLNotNull - @SQLLimitSize(128) - @SQLComment("Mime -type of the media") - public String mimeType; - @SQLNotNull - @SQLComment("Size in Byte of the data") - public Long size; + @Column(length = 128, nullable = false) + @SQLComment("Sha512 of the data") + public String sha512; + @Column(length = 128, nullable = false) + @SQLComment("Mime -type of the media") + public String mimeType; + @Column(nullable = false) + @SQLComment("Size in Byte of the data") + public Long size; } diff --git a/src/org/kar/archidata/model/GenericTable.java b/src/org/kar/archidata/model/GenericTable.java index 5a3a7db..20fb800 100644 --- a/src/org/kar/archidata/model/GenericTable.java +++ b/src/org/kar/archidata/model/GenericTable.java @@ -2,38 +2,40 @@ package org.kar.archidata.model; import java.sql.Timestamp; -import org.kar.archidata.annotation.SQLAutoIncrement; +import org.kar.archidata.annotation.CreationTimestamp; import org.kar.archidata.annotation.SQLComment; -import org.kar.archidata.annotation.SQLCreateTime; import org.kar.archidata.annotation.SQLDefault; import org.kar.archidata.annotation.SQLDeleted; -import org.kar.archidata.annotation.SQLNotNull; import org.kar.archidata.annotation.SQLNotRead; -import org.kar.archidata.annotation.SQLPrimaryKey; -import org.kar.archidata.annotation.SQLUpdateTime; +import org.kar.archidata.annotation.UpdateTimestamp; + +import jakarta.persistence.Column; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; public class GenericTable { - @SQLAutoIncrement // Add AUTO_INCREMENT modifier - @SQLPrimaryKey // Create a PRIMARY KEY based on this field - @SQLNotNull - @SQLComment("Primary key of the base") + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(nullable = false, unique = true) + @SQLComment("Primary key of the base") public Long id = null; - @SQLNotRead - @SQLNotNull - @SQLDefault("'0'") - @SQLDeleted - @SQLComment("When delete, they are not removed, they are just set in a deleted state") + @SQLNotRead + @Column(nullable = false) + @SQLDefault("'0'") + @SQLDeleted + @SQLComment("When delete, they are not removed, they are just set in a deleted state") public Boolean deleted = null; - @SQLNotRead - @SQLCreateTime - @SQLNotNull - @SQLComment("Create time of the object") - @SQLDefault("CURRENT_TIMESTAMP(3)") + @SQLNotRead + @CreationTimestamp + @Column(nullable = false) + @SQLComment("Create time of the object") + @SQLDefault("CURRENT_TIMESTAMP(3)") public Timestamp create_date = null; - @SQLNotRead - @SQLUpdateTime - @SQLNotNull - @SQLComment("When update the object") - @SQLDefault("CURRENT_TIMESTAMP(3)") + @SQLNotRead + @UpdateTimestamp + @Column(nullable = false) + @SQLComment("When update the object") + @SQLDefault("CURRENT_TIMESTAMP(3)") public Timestamp modify_date = null; } diff --git a/src/org/kar/archidata/model/GenericToken.java b/src/org/kar/archidata/model/GenericToken.java index 5f6195d..ed56849 100644 --- a/src/org/kar/archidata/model/GenericToken.java +++ b/src/org/kar/archidata/model/GenericToken.java @@ -3,21 +3,22 @@ package org.kar.archidata.model; import java.sql.Timestamp; import org.kar.archidata.annotation.SQLIfNotExists; -import org.kar.archidata.annotation.SQLNotNull; -import org.kar.archidata.annotation.SQLTableName; import com.fasterxml.jackson.annotation.JsonInclude; -@SQLTableName ("applicationToken") +import jakarta.persistence.Column; +import jakarta.persistence.Table; + +@Table(name = "applicationToken") @SQLIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class GenericToken extends GenericTable { - @SQLNotNull - public Long parentId; - @SQLNotNull - public String name; - @SQLNotNull - public Timestamp endValidityTime = null; - @SQLNotNull - public String token; + @Column(nullable = false) + public Long parentId; + @Column(nullable = false) + public String name; + @Column(nullable = false) + public Timestamp endValidityTime = null; + @Column(nullable = false) + public String token; } diff --git a/src/org/kar/archidata/model/GetToken.java b/src/org/kar/archidata/model/GetToken.java index 1f6390e..a57eb03 100644 --- a/src/org/kar/archidata/model/GetToken.java +++ b/src/org/kar/archidata/model/GetToken.java @@ -3,6 +3,7 @@ package org.kar.archidata.model; import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.NON_NULL) -public record GetToken(String jwt) { +public record GetToken( + String jwt) { } diff --git a/src/org/kar/archidata/model/Migration.java b/src/org/kar/archidata/model/Migration.java index 66a1bb6..f8e942c 100644 --- a/src/org/kar/archidata/model/Migration.java +++ b/src/org/kar/archidata/model/Migration.java @@ -1,6 +1,6 @@ package org.kar.archidata.model; -public class Migration extends GenericTable{ - public String migrationId; - +public class Migration extends GenericTable { + public String migrationId; + } diff --git a/src/org/kar/archidata/model/Token.java b/src/org/kar/archidata/model/Token.java index 61f1ae6..28da800 100644 --- a/src/org/kar/archidata/model/Token.java +++ b/src/org/kar/archidata/model/Token.java @@ -3,46 +3,38 @@ package org.kar.archidata.model; import java.sql.ResultSet; import java.sql.SQLException; - public class Token { - public Long id; - public Long userId; - public String token; - public String createTime; - public String endValidityTime; - - public Token() { - } - - public Token(long id, long userId, String token, String createTime, String endValidityTime) { - this.id = id; - this.userId = userId; - this.token = token; - this.createTime = createTime; - this.endValidityTime = endValidityTime; - } - - public Token(ResultSet rs) { - int iii = 1; - try { - this.id = rs.getLong(iii++); - this.userId = rs.getLong(iii++); - this.token = rs.getString(iii++); - this.createTime = rs.getString(iii++); - this.endValidityTime = rs.getString(iii++); - } catch (SQLException ex) { - ex.printStackTrace(); - } - } - - @Override - public String toString() { - return "Token{" + - "id=" + id + - ", userId=" + userId + - ", token='" + token + '\'' + - ", createTime=" + createTime + - ", endValidityTime=" + endValidityTime + - '}'; - } + public Long id; + public Long userId; + public String token; + public String createTime; + public String endValidityTime; + + public Token() {} + + public Token(long id, long userId, String token, String createTime, String endValidityTime) { + this.id = id; + this.userId = userId; + this.token = token; + this.createTime = createTime; + this.endValidityTime = endValidityTime; + } + + public Token(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.userId = rs.getLong(iii++); + this.token = rs.getString(iii++); + this.createTime = rs.getString(iii++); + this.endValidityTime = rs.getString(iii++); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + + @Override + public String toString() { + return "Token{" + "id=" + id + ", userId=" + userId + ", token='" + token + '\'' + ", createTime=" + createTime + ", endValidityTime=" + endValidityTime + '}'; + } } diff --git a/src/org/kar/archidata/model/User.java b/src/org/kar/archidata/model/User.java index 30a44c6..c5acec3 100644 --- a/src/org/kar/archidata/model/User.java +++ b/src/org/kar/archidata/model/User.java @@ -15,35 +15,43 @@ CREATE TABLE `user` ( */ import java.sql.Timestamp; +import java.util.List; import org.kar.archidata.annotation.SQLDefault; import org.kar.archidata.annotation.SQLIfNotExists; -import org.kar.archidata.annotation.SQLLimitSize; -import org.kar.archidata.annotation.SQLNotNull; -import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.sqlWrapper.Foreign; import com.fasterxml.jackson.annotation.JsonInclude; -@SQLTableName ("user") +import jakarta.persistence.Column; +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +@Table(name = "user") @SQLIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class User extends GenericTable { - @SQLLimitSize(128) - public String login = null; - - public Timestamp lastConnection = null; - @SQLDefault("'0'") - @SQLNotNull - public boolean admin = false; - @SQLDefault("'0'") - @SQLNotNull - public boolean blocked = false; - @SQLDefault("'0'") - @SQLNotNull - public boolean removed = false; + @Column(length = 128) + public String login = null; + + public Timestamp lastConnection = null; + @SQLDefault("'0'") + @Column(nullable = false) + public boolean admin = false; + @SQLDefault("'0'") + @Column(nullable = false) + public boolean blocked = false; + @SQLDefault("'0'") + @Column(nullable = false) + public boolean removed = false; + + @ManyToOne(fetch = FetchType.LAZY) + public List> covers; + @Override public String toString() { - return "User [login=" + login + ", last=" + lastConnection + ", admin=" + admin + "]"; + return "User [login=" + this.login + ", last=" + this.lastConnection + ", admin=" + this.admin + "]"; } - + } diff --git a/src/org/kar/archidata/model/UserByToken.java b/src/org/kar/archidata/model/UserByToken.java index c97b4f6..bf274bb 100644 --- a/src/org/kar/archidata/model/UserByToken.java +++ b/src/org/kar/archidata/model/UserByToken.java @@ -3,7 +3,6 @@ package org.kar.archidata.model; import java.util.HashMap; import java.util.Map; - public class UserByToken { public static final int TYPE_USER = -1; public static final int TYPE_APPLICATION = -2; @@ -11,49 +10,49 @@ public class UserByToken { public Integer type = null; public Long id = null; - public Long parentId = null; // FOr application, this is the id of the application, and of user token, this is the USERID - public String name = null; - // Right map - public Map right = new HashMap<>(); - - public boolean hasRight(String key, Object value) { - if (! this.right.containsKey(key)) { - return false; - } - Object data = this.right.get(key); - if (data instanceof Boolean elem) { - if (value instanceof Boolean castVal) { - if (elem == castVal) { - return true; - } - } - return false; - } - if (data instanceof String elem) { - if (value instanceof String castVal) { - if (elem.equals(castVal)) { - return true; - } - } - return false; - } - if (data instanceof Long elem) { - if (value instanceof Long castVal) { - if (elem == castVal) { - return true; - } - } - return false; - } - if (data instanceof Double elem) { - if (value instanceof Double castVal) { - if (elem == castVal) { - return true; - } - } - return false; - } - return false; - } - + public Long parentId = null; // FOr application, this is the id of the application, and of user token, this is the USERID + public String name = null; + // Right map + public Map right = new HashMap<>(); + + public boolean hasRight(String key, Object value) { + if (!this.right.containsKey(key)) { + return false; + } + Object data = this.right.get(key); + if (data instanceof Boolean elem) { + if (value instanceof Boolean castVal) { + if (elem == castVal) { + return true; + } + } + return false; + } + if (data instanceof String elem) { + if (value instanceof String castVal) { + if (elem.equals(castVal)) { + return true; + } + } + return false; + } + if (data instanceof Long elem) { + if (value instanceof Long castVal) { + if (elem == castVal) { + return true; + } + } + return false; + } + if (data instanceof Double elem) { + if (value instanceof Double castVal) { + if (elem == castVal) { + return true; + } + } + return false; + } + return false; + } + } diff --git a/src/org/kar/archidata/sqlWrapper/Foreign.java b/src/org/kar/archidata/sqlWrapper/Foreign.java new file mode 100644 index 0000000..15ba153 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/Foreign.java @@ -0,0 +1,16 @@ +package org.kar.archidata.sqlWrapper; + +public class Foreign { + public final Long id; + public final T data; + + public Foreign(final Long id) { + this.id = id; + this.data = null; + } + + public Foreign(final T data) { + this.id = null; + this.data = data; + } +} diff --git a/src/org/kar/archidata/sqlWrapper/GenericAddOn.java b/src/org/kar/archidata/sqlWrapper/GenericAddOn.java new file mode 100644 index 0000000..31d60cb --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/GenericAddOn.java @@ -0,0 +1,11 @@ +package org.kar.archidata.sqlWrapper; + +import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalForeinKeyAsList; +import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalLink; + +public class GenericAddOn { + public static void addGenericAddOn() { + SqlWrapper.addAddOn(new AddOnSQLTableExternalLink()); + SqlWrapper.addAddOn(new AddOnSQLTableExternalForeinKeyAsList()); + } +} diff --git a/src/org/kar/archidata/sqlWrapper/QuerryAnd.java b/src/org/kar/archidata/sqlWrapper/QuerryAnd.java new file mode 100644 index 0000000..d2a077e --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/QuerryAnd.java @@ -0,0 +1,43 @@ +package org.kar.archidata.sqlWrapper; + +import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.List; + +public class QuerryAnd implements QuerryItem { + protected final List childs; + + public QuerryAnd(List childs) { + this.childs = childs; + } + + public QuerryAnd(QuerryItem... items) { + this.childs = new ArrayList<>(); + for (int iii = 0; iii < items.length; iii++) { + this.childs.add(items[iii]); + } + } + + public void generateQuerry(StringBuilder querry, String tableName) { + querry.append(" ("); + boolean first = false; + for (QuerryItem elem : this.childs) { + if (first) { + first = false; + } else { + querry.append(" AND "); + } + elem.generateQuerry(querry, tableName); + } + querry.append(")"); + } + + @Override + public int injectQuerry(PreparedStatement ps, int iii) throws Exception { + + for (QuerryItem elem : this.childs) { + iii = elem.injectQuerry(ps, iii); + } + return iii; + } +} diff --git a/src/org/kar/archidata/sqlWrapper/QuerryCondition.java b/src/org/kar/archidata/sqlWrapper/QuerryCondition.java new file mode 100644 index 0000000..50f3dd2 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/QuerryCondition.java @@ -0,0 +1,31 @@ +package org.kar.archidata.sqlWrapper; + +import java.sql.PreparedStatement; + +public class QuerryCondition implements QuerryItem { + private final String key; + private final String comparator; + private final Object value; + + public QuerryCondition(String key, String comparator, Object value) { + this.key = key; + this.comparator = comparator; + this.value = value; + } + + public void generateQuerry(StringBuilder querry, String tableName) { + querry.append(tableName); + querry.append("."); + querry.append(this.key); + querry.append(" "); + querry.append(this.comparator); + querry.append(" ?"); + + } + + @Override + public int injectQuerry(PreparedStatement ps, int iii) throws Exception { + SqlWrapper.addElement(ps, this.value, iii++); + return iii; + } +} diff --git a/src/org/kar/archidata/sqlWrapper/QuerryItem.java b/src/org/kar/archidata/sqlWrapper/QuerryItem.java new file mode 100644 index 0000000..8a12e1a --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/QuerryItem.java @@ -0,0 +1,9 @@ +package org.kar.archidata.sqlWrapper; + +import java.sql.PreparedStatement; + +public interface QuerryItem { + void generateQuerry(StringBuilder querry, String tableName); + + int injectQuerry(PreparedStatement ps, int iii) throws Exception; +} diff --git a/src/org/kar/archidata/sqlWrapper/QuerryOr.java b/src/org/kar/archidata/sqlWrapper/QuerryOr.java new file mode 100644 index 0000000..21d7a11 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/QuerryOr.java @@ -0,0 +1,35 @@ +package org.kar.archidata.sqlWrapper; + +import java.sql.PreparedStatement; +import java.util.List; + +public class QuerryOr implements QuerryItem { + protected final List childs; + + public QuerryOr(List childs) { + this.childs = childs; + } + + public void generateQuerry(StringBuilder querry, String tableName) { + querry.append(" ("); + boolean first = false; + for (QuerryItem elem : this.childs) { + if (first) { + first = false; + } else { + querry.append(" OR "); + } + elem.generateQuerry(querry, tableName); + } + querry.append(")"); + } + + @Override + public int injectQuerry(PreparedStatement ps, int iii) throws Exception { + + for (QuerryItem elem : this.childs) { + iii = elem.injectQuerry(ps, iii); + } + return iii; + } +} diff --git a/src/org/kar/archidata/sqlWrapper/SqlWrapper.java b/src/org/kar/archidata/sqlWrapper/SqlWrapper.java index f2d5da7..9bcffd2 100644 --- a/src/org/kar/archidata/sqlWrapper/SqlWrapper.java +++ b/src/org/kar/archidata/sqlWrapper/SqlWrapper.java @@ -1,28 +1,29 @@ package org.kar.archidata.sqlWrapper; import java.io.IOException; -import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.stream.Collectors; -import java.sql.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import org.kar.archidata.GlobalConfiguration; -import org.kar.archidata.annotation.SQLAutoIncrement; -import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.annotation.CreationTimestamp; +import org.kar.archidata.annotation.SQLAddOn; +import org.kar.archidata.annotation.SQLDefault; +import org.kar.archidata.annotation.SQLDeleted; import org.kar.archidata.annotation.SQLIfNotExists; -import org.kar.archidata.annotation.SQLLimitSize; -import org.kar.archidata.annotation.SQLNotNull; import org.kar.archidata.annotation.SQLNotRead; -import org.kar.archidata.annotation.SQLPrimaryKey; -import org.kar.archidata.annotation.SQLTableLinkGeneric; -import org.kar.archidata.annotation.SQLTableLinkGeneric.ModelLink; -import org.kar.archidata.annotation.SQLTableName; -import org.kar.archidata.annotation.SQLUpdateTime; +import org.kar.archidata.annotation.UpdateTimestamp; import org.kar.archidata.db.DBEntry; import org.kar.archidata.util.ConfigBaseVariable; import org.slf4j.Logger; @@ -31,34 +32,32 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.persistence.GenerationType; import jakarta.ws.rs.InternalServerErrorException; -import org.kar.archidata.annotation.SQLCreateTime; -import org.kar.archidata.annotation.SQLDefault; -import org.kar.archidata.annotation.SQLDeleted; - public class SqlWrapper { static final Logger LOGGER = LoggerFactory.getLogger(SqlWrapper.class); static final List addOn = new ArrayList<>(); - - public static void addAddOn(SqlWrapperAddOn addOn) { + + public static void addAddOn(final SqlWrapperAddOn addOn) { SqlWrapper.addOn.add(addOn); }; - + public static class ExceptionDBInterface extends Exception { private static final long serialVersionUID = 1L; public int errorID; - ExceptionDBInterface(int errorId, String message) { + + public ExceptionDBInterface(final int errorId, final String message) { super(message); this.errorID = errorId; } } - + public SqlWrapper() { - + } - public static boolean isDBExist(String name) throws InternalServerErrorException { + public static boolean isDBExist(final String name) throws InternalServerErrorException { if (ConfigBaseVariable.getDBType().equals("sqlite")) { // no base manage in sqLite ... // TODO: check if the file exist or not ... @@ -67,7 +66,7 @@ public class SqlWrapper { DBEntry entry; try { entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, true); - } catch (IOException ex) { + } catch (final IOException ex) { // TODO Auto-generated catch block ex.printStackTrace(); LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); @@ -75,31 +74,32 @@ public class SqlWrapper { } try { // TODO : Maybe connect with a temporary not specified connection interface to a db ... - PreparedStatement ps = entry.connection.prepareStatement("show databases"); - ResultSet rs = ps.executeQuery(); - //LOGGER.info("List all tables: equals? '{}'", name); - while (rs.next()) { - String data = rs.getString(1); - //LOGGER.info(" - '{}'", data); - if (name.equals(data)) { - return true; - } - } + final PreparedStatement ps = entry.connection.prepareStatement("show databases"); + final ResultSet rs = ps.executeQuery(); + //LOGGER.info("List all tables: equals? '{}'", name); + while (rs.next()) { + final String data = rs.getString(1); + //LOGGER.info(" - '{}'", data); + if (name.equals(data)) { + return true; + } + } return false; - } catch (SQLException ex) { + } catch (final SQLException ex) { LOGGER.error("Can not check if the DB exist SQL-error !!! {}", ex.getMessage()); } finally { - try { + try { entry.close(); - } catch (IOException e) { + } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } - entry = null; + entry = null; } throw new InternalServerErrorException("Can Not manage the DB-access"); } - public static boolean createDB(String name) { + + public static boolean createDB(final String name) { if (ConfigBaseVariable.getDBType().equals("sqlite")) { // no base manage in sqLite ... // TODO: check if the file exist or not ... @@ -107,17 +107,18 @@ public class SqlWrapper { } try { return 1 == SqlWrapper.executeSimpleQuerry("CREATE DATABASE `" + name + "`;", true); - } catch (SQLException ex) { + } catch (final SQLException ex) { ex.printStackTrace(); LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); return false; - } catch (IOException ex) { + } catch (final IOException ex) { ex.printStackTrace(); LOGGER.error("Can not check if the DB exist!!! {}", ex.getMessage()); return false; } } - public static boolean isTableExist(String name) throws InternalServerErrorException { + + public static boolean isTableExist(final String name) throws InternalServerErrorException { try { String request = ""; if (ConfigBaseVariable.getDBType().equals("sqlite")) { @@ -128,41 +129,41 @@ public class SqlWrapper { AND name = ?; """; // PreparedStatement ps = entry.connection.prepareStatement("show tables"); - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - PreparedStatement ps = entry.connection.prepareStatement(request); + final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final PreparedStatement ps = entry.connection.prepareStatement(request); ps.setString(1, name); - ResultSet ret = ps.executeQuery(); - int count = ret.getInt("total"); + final ResultSet ret = ps.executeQuery(); + final int count = ret.getInt("total"); return count == 1; } else { - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); // TODO : Maybe connect with a temporary not specified connection interface to a db ... - PreparedStatement ps = entry.connection.prepareStatement("show tables"); - ResultSet rs = ps.executeQuery(); - //LOGGER.info("List all tables: equals? '{}'", name); - while (rs.next()) { - String data = rs.getString(1); - //LOGGER.info(" - '{}'", data); - if (name.equals(data)) { - return true; - } - } + final PreparedStatement ps = entry.connection.prepareStatement("show tables"); + final ResultSet rs = ps.executeQuery(); + //LOGGER.info("List all tables: equals? '{}'", name); + while (rs.next()) { + final String data = rs.getString(1); + //LOGGER.info(" - '{}'", data); + if (name.equals(data)) { + return true; + } + } return false; } - } catch (SQLException ex) { + } catch (final SQLException ex) { LOGGER.error("Can not check if the table exist SQL-error !!! {}", ex.getMessage()); - } catch (IOException ex) { + } catch (final IOException ex) { LOGGER.error("Can not check if the table exist!!! {}", ex.getMessage()); } throw new InternalServerErrorException("Can Not manage the DB-access"); - } - - public static String convertTypeInSQL(Class type) throws Exception { + } + + public static String convertTypeInSQL(final Class type) throws Exception { if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - if (type == Long.class || type == long.class ) { + if (type == Long.class || type == long.class) { return "bigint"; } - if (type == Integer.class || type == int.class ) { + if (type == Integer.class || type == int.class) { return "int"; } if (type == Boolean.class || type == boolean.class) { @@ -184,10 +185,10 @@ public class SqlWrapper { return "text"; } } else { - if (type == Long.class || type == long.class ) { + if (type == Long.class || type == long.class) { return "INTEGER"; } - if (type == Integer.class || type == int.class ) { + if (type == Integer.class || type == int.class) { return "INTEGER"; } if (type == Boolean.class || type == boolean.class) { @@ -212,163 +213,166 @@ public class SqlWrapper { throw new Exception("Imcompatible type of element in object for: " + type.getCanonicalName()); } - protected static void setValuedb(Class type, T data, int index, Field field, PreparedStatement ps) throws IllegalArgumentException, IllegalAccessException, SQLException { + protected static void setValuedb(final Class type, final T data, int index, final Field field, final PreparedStatement ps) + throws IllegalArgumentException, IllegalAccessException, SQLException { if (type == Long.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.BIGINT); - } else { - ps.setLong(index++, (Long)tmp); - } - } else if (type == long.class ) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.BIGINT); + } else { + ps.setLong(index++, (Long) tmp); + } + } else if (type == long.class) { ps.setLong(index++, field.getLong(data)); } else if (type == Integer.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.INTEGER); - } else { - ps.setInt(index++, (Integer)tmp); - } - } else if (type == int.class ) { + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setInt(index++, (Integer) tmp); + } + } else if (type == int.class) { ps.setInt(index++, field.getInt(data)); } else if (type == Float.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.FLOAT); - } else { - ps.setFloat(index++, (Float)tmp); - } + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.FLOAT); + } else { + ps.setFloat(index++, (Float) tmp); + } } else if (type == float.class) { ps.setFloat(index++, field.getFloat(data)); } else if (type == Double.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.DOUBLE); - } else { - ps.setDouble(index++, (Double)tmp); - } + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.DOUBLE); + } else { + ps.setDouble(index++, (Double) tmp); + } } else if (type == Double.class) { ps.setDouble(index++, field.getDouble(data)); } else if (type == Boolean.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.INTEGER); - } else { - ps.setBoolean(index++, (Boolean)tmp); - } + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setBoolean(index++, (Boolean) tmp); + } } else if (type == boolean.class) { ps.setBoolean(index++, field.getBoolean(data)); } else if (type == Timestamp.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.INTEGER); - } else { - ps.setTimestamp(index++, (Timestamp)tmp); - } + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setTimestamp(index++, (Timestamp) tmp); + } } else if (type == Date.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.INTEGER); - } else { - ps.setDate(index++, (Date)tmp); - } + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setDate(index++, (Date) tmp); + } } else if (type == String.class) { - Object tmp = field.get(data); - if (tmp == null) { - ps.setNull(index++, Types.VARCHAR); - } else { - ps.setString(index++, (String)tmp); - } + final Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.VARCHAR); + } else { + ps.setString(index++, (String) tmp); + } } } - protected static void setValueFromDb(Class type, T data, int index, Field field, ResultSet rs) throws IllegalArgumentException, IllegalAccessException, SQLException { + + protected static void setValueFromDb(final Class type, final T data, final int index, final Field field, final ResultSet rs) + throws IllegalArgumentException, IllegalAccessException, SQLException { if (type == Long.class) { - Long tmp = rs.getLong(index); + final Long tmp = rs.getLong(index); if (rs.wasNull()) { field.set(data, null); } else { //logger.debug(" ==> {}", tmp); field.set(data, tmp); } - } else if (type == long.class ) { - Long tmp = rs.getLong(index); + } else if (type == long.class) { + final Long tmp = rs.getLong(index); if (rs.wasNull()) { //field.set(data, null); } else { field.setLong(data, tmp); } } else if (type == Integer.class) { - Integer tmp = rs.getInt(index); + final Integer tmp = rs.getInt(index); if (rs.wasNull()) { field.set(data, null); } else { field.set(data, tmp); } - } else if (type == int.class ) { - Integer tmp = rs.getInt(index); + } else if (type == int.class) { + final Integer tmp = rs.getInt(index); if (rs.wasNull()) { //field.set(data, null); } else { field.setInt(data, tmp); } } else if (type == Float.class) { - Float tmp = rs.getFloat(index); + final Float tmp = rs.getFloat(index); if (rs.wasNull()) { field.set(data, null); } else { field.set(data, tmp); } } else if (type == float.class) { - Float tmp = rs.getFloat(index); + final Float tmp = rs.getFloat(index); if (rs.wasNull()) { //field.set(data, null); } else { field.setFloat(data, tmp); } } else if (type == Double.class) { - Double tmp = rs.getDouble(index); + final Double tmp = rs.getDouble(index); if (rs.wasNull()) { field.set(data, null); } else { field.set(data, tmp); } } else if (type == double.class) { - Double tmp = rs.getDouble(index); + final Double tmp = rs.getDouble(index); if (rs.wasNull()) { //field.set(data, null); } else { field.setDouble(data, tmp); } } else if (type == Boolean.class) { - Boolean tmp = rs.getBoolean(index); + final Boolean tmp = rs.getBoolean(index); if (rs.wasNull()) { field.set(data, null); } else { field.set(data, tmp); } } else if (type == boolean.class) { - Boolean tmp = rs.getBoolean(index); + final Boolean tmp = rs.getBoolean(index); if (rs.wasNull()) { //field.set(data, null); } else { field.setBoolean(data, tmp); } } else if (type == Timestamp.class) { - Timestamp tmp = rs.getTimestamp(index); + final Timestamp tmp = rs.getTimestamp(index); if (rs.wasNull()) { field.set(data, null); } else { field.set(data, tmp); } } else if (type == Date.class) { - Date tmp = rs.getDate(index); + final Date tmp = rs.getDate(index); if (rs.wasNull()) { field.set(data, null); } else { field.set(data, tmp); } } else if (type == String.class) { - String tmp = rs.getString(index); + final String tmp = rs.getString(index); if (rs.wasNull()) { field.set(data, null); } else { @@ -376,187 +380,187 @@ public class SqlWrapper { } } } - public static ModelLink getLinkMode(Field elem) { - SQLTableLinkGeneric[] decorators = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class); - if (decorators == null || decorators.length == 0) { - return SQLTableLinkGeneric.ModelLink.NONE; - } - return decorators[0].value(); + + public static boolean isAddOnField(final Field field) { + return AnnotationTools.isAnnotationGroup(field, SQLAddOn.class); } - public static T insert(T data) throws Exception { - Class clazz = data.getClass(); - //public static NodeSmall createNode(String typeInNode, String name, String descrition, Long parentId) { - - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - // real add in the BDD: - try { - String tableName = getTableName(clazz); - //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - StringBuilder query = new StringBuilder(); - query.append("INSERT INTO `"); - query.append(tableName); - query.append("` ("); + public static SqlWrapperAddOn findAddOnforField(final Field field) { + for (final SqlWrapperAddOn elem : addOn) { + if (elem.isCompatibleField(field)) { + return elem; + } + } + return null; + } - boolean firstField = true; - int count = 0; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; - if (primaryKey) { + public static T insert(final T data) throws Exception { + final Class clazz = data.getClass(); + //public static NodeSmall createNode(String typeInNode, String name, String descrition, Long parentId) { + + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + // real add in the BDD: + try { + final String tableName = AnnotationTools.getTableName(clazz); + //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final StringBuilder querry = new StringBuilder(); + querry.append("INSERT INTO `"); + querry.append(tableName); + querry.append("` ("); + + boolean firstField = true; + int count = 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; } - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric == ModelLink.EXTERNAL) { + if (AnnotationTools.isPrimaryKey(elem)) { continue; } - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null && addOn.isExternal()) { + continue; + } + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; if (createTime) { continue; } - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; if (updateTime) { continue; } if (!elem.getClass().isPrimitive()) { - Object tmp = elem.get(data); - if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + final Object tmp = elem.get(data); + if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { continue; } } count++; - String name = elem.getName(); + final String name = elem.getName(); if (firstField) { - firstField = false; + firstField = false; } else { - query.append(","); + querry.append(","); } - query.append(" `"); - query.append(name); - query.append("`"); - } - firstField = true; - query.append(") VALUES ("); - for (int iii = 0; iii remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; - if (primaryKey) { + querry.append("?"); + } + querry.append(")"); + //LOGGER.warn("generate the querry: '{}'", querry.toString()); + // prepare the request: + final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); + Field primaryKeyField = null; + int iii = 1; + 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; + } + if (AnnotationTools.isPrimaryKey(elem)) { primaryKeyField = elem; continue; } - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric == ModelLink.EXTERNAL) { + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null && addOn.isExternal()) { continue; } - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; if (createTime) { continue; } - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; if (updateTime) { continue; } - if (linkGeneric == ModelLink.NONE) { - Class type = elem.getType(); + if (addOn != null) { + // Add-on specific insertion. + final Object tmp = elem.get(data); + iii = addOn.insertData(ps, tmp, iii); + } else { + // Generic class insertion... + final Class type = elem.getType(); if (!type.isPrimitive()) { - Object tmp = elem.get(data); - if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + final Object tmp = elem.get(data); + if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { continue; } } setValuedb(type, data, iii++, elem, ps); - } else { - // transform the data in string to insert it ... - Object tmp = elem.get(data); - if (tmp == null) { - ps.setNull(iii++, Types.BIGINT); - } else { - @SuppressWarnings("unchecked") - String dataTmp = getStringOfIds((List)tmp); - ps.setString(iii++, dataTmp); - } } count++; - } - // execute the request - int affectedRows = ps.executeUpdate(); - if (affectedRows == 0) { - throw new SQLException("Creating node failed, no rows affected."); - } - Long uniqueSQLID = null; - // Retrieve uid inserted - try (ResultSet generatedKeys = ps.getGeneratedKeys()) { - if (generatedKeys.next()) { - uniqueSQLID = generatedKeys.getLong(1); - } else { - throw new SQLException("Creating node failed, no ID obtained (1)."); - } - } catch (Exception ex) { - LOGGER.error("Can not get the UID key inserted ... "); - ex.printStackTrace(); - throw new SQLException("Creating node failed, no ID obtained (2)."); - } - if (primaryKeyField != null) { - if (primaryKeyField.getType() == Long.class) { - primaryKeyField.set(data, (Long)uniqueSQLID); - } else if (primaryKeyField.getType() == long.class) { - primaryKeyField.setLong(data, uniqueSQLID); - } else { - LOGGER.error("Can not manage the primary filed !!!"); - } - } - //ps.execute(); - } catch (SQLException ex) { - ex.printStackTrace(); - } finally { - entry.close(); - entry = null; - } - return data; + } + // execute the request + final int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating node failed, no rows affected."); + } + Long uniqueSQLID = null; + // Retrieve uid inserted + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + uniqueSQLID = generatedKeys.getLong(1); + } else { + throw new SQLException("Creating node failed, no ID obtained (1)."); + } + } catch (final Exception ex) { + LOGGER.error("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating node failed, no ID obtained (2)."); + } + if (primaryKeyField != null) { + if (primaryKeyField.getType() == Long.class) { + primaryKeyField.set(data, uniqueSQLID); + } else if (primaryKeyField.getType() == long.class) { + primaryKeyField.setLong(data, uniqueSQLID); + } else { + LOGGER.error("Can not manage the primary filed !!!"); + } + } + //ps.execute(); + } catch (final SQLException ex) { + ex.printStackTrace(); + } finally { + entry.close(); + entry = null; + } + return data; } + // seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated... - public static T insertWithJson(Class clazz, String jsonData) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - // parse the object to be sure the data are valid: - T data = mapper.readValue(jsonData, clazz); - - return insert(data); + public static T insertWithJson(final Class clazz, final String jsonData) throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + final T data = mapper.readValue(jsonData, clazz); + + return insert(data); } - - public static int update(Class clazz, long id, String jsonData) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - // parse the object to be sure the data are valid: - T data = mapper.readValue(jsonData, clazz); - // Read the tree to filter injection of data: - JsonNode root = mapper.readTree(jsonData); - List keys = new ArrayList<>(); - Iterator iterator = root.fieldNames(); - iterator.forEachRemaining(e -> keys.add(e)); - return update(data, id, keys); + + public static int update(final Class clazz, final long id, final String jsonData) throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + final T data = mapper.readValue(jsonData, clazz); + // Read the tree to filter injection of data: + final JsonNode root = mapper.readTree(jsonData); + final List keys = new ArrayList<>(); + final Iterator iterator = root.fieldNames(); + iterator.forEachRemaining(e -> keys.add(e)); + return update(data, id, keys); } - + /** - * + * * @param * @param data * @param id @@ -564,732 +568,649 @@ public class SqlWrapper { * @return the affected rows. * @throws Exception */ - public static int update(T data, long id, List filterValue) throws Exception { - Class clazz = data.getClass(); + public static int update(final T data, final long id, final List filterValue) throws Exception { + final Class clazz = data.getClass(); //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { - - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - // real add in the BDD: - try { - String tableName = getTableName(clazz); - //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - StringBuilder query = new StringBuilder(); - query.append("UPDATE `"); - query.append(tableName); - query.append("` SET "); - boolean firstField = true; - Field primaryKeyField = null; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; - if (primaryKey) { + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + // real add in the BDD: + try { + final String tableName = AnnotationTools.getTableName(clazz); + //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final StringBuilder querry = new StringBuilder(); + querry.append("UPDATE `"); + querry.append(tableName); + querry.append("` SET "); + + boolean firstField = true; + Field primaryKeyField = null; + 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; + } + if (AnnotationTools.isPrimaryKey(elem)) { primaryKeyField = elem; continue; } - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric == ModelLink.EXTERNAL) { + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null && addOn.isExternal()) { continue; } - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; if (createTime) { continue; } - String name = elem.getName(); - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; - if (! updateTime && !filterValue.contains(name)) { + final String name = elem.getName(); + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; + if (!updateTime && !filterValue.contains(name)) { continue; } if (!elem.getClass().isPrimitive()) { - Object tmp = elem.get(data); - if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + final Object tmp = elem.get(data); + if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { continue; } } if (firstField) { - firstField = false; + firstField = false; } else { - query.append(","); + querry.append(","); } - query.append(" `"); - query.append(name); - query.append("` = "); - if (updateTime) { - query.append(getDBNow()); - query.append(" "); - } else { - query.append("? "); - } - } - query.append(" WHERE `"); - query.append(primaryKeyField.getName()); - query.append("` = ?"); - firstField = true; - // logger.debug("generate the querry: '{}'", query.toString()); - // prepare the request: - PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); - int iii = 1; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; - if (primaryKey) { + querry.append(" `"); + querry.append(name); + querry.append("` = "); + if (updateTime) { + querry.append(getDBNow()); + querry.append(" "); + } else { + querry.append("? "); + } + } + querry.append(" WHERE `"); + querry.append(primaryKeyField.getName()); + querry.append("` = ?"); + firstField = true; + // logger.debug("generate the querry: '{}'", querry.toString()); + // prepare the request: + final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + 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; } - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric == ModelLink.EXTERNAL) { + if (AnnotationTools.isPrimaryKey(elem)) { continue; } - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canUpdate()) { + continue; + } + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; if (createTime) { continue; } - String name = elem.getName(); - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + final String name = elem.getName(); + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; if (updateTime || !filterValue.contains(name)) { continue; } - if (linkGeneric == ModelLink.NONE) { - Class type = elem.getType(); + if (addOn == null) { + final Class type = elem.getType(); if (!type.isPrimitive()) { - Object tmp = elem.get(data); - if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + final Object tmp = elem.get(data); + if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { continue; } } setValuedb(type, data, iii++, elem, ps); } else { - // transform the data in string to insert it ... - Object tmp = elem.get(data); - if (tmp == null) { - ps.setNull(iii++, Types.BIGINT); - } else { - @SuppressWarnings("unchecked") - String dataTmp = getStringOfIds((List)tmp); - ps.setString(iii++, dataTmp); - } + iii = addOn.insertData(ps, data, iii); } - } - ps.setLong(iii++, id); - // execute the request - int affectedRows = ps.executeUpdate(); - return affectedRows; - } catch (SQLException ex) { - ex.printStackTrace(); - } finally { - entry.close(); - entry = null; - } - return 0; + } + ps.setLong(iii++, id); + // execute the request + final int affectedRows = ps.executeUpdate(); + return affectedRows; + } catch (final SQLException ex) { + ex.printStackTrace(); + } finally { + entry.close(); + entry = null; + } + return 0; } - static void addElement(PreparedStatement ps, Object value, int iii) throws Exception { - if (value.getClass() == Long.class) { - ps.setLong(iii, (Long)value); + static void addElement(final PreparedStatement ps, final Object value, final int iii) throws Exception { + if (value.getClass() == Long.class) { + ps.setLong(iii, (Long) value); } else if (value.getClass() == Integer.class) { - ps.setInt(iii, (Integer)value); + ps.setInt(iii, (Integer) value); } else if (value.getClass() == String.class) { - ps.setString(iii, (String)value); + ps.setString(iii, (String) value); } else if (value.getClass() == Short.class) { - ps.setShort(iii, (Short)value); + ps.setShort(iii, (Short) value); } else if (value.getClass() == Byte.class) { - ps.setByte(iii, (Byte)value); + ps.setByte(iii, (Byte) value); } else if (value.getClass() == Float.class) { - ps.setFloat(iii, (Float)value); + ps.setFloat(iii, (Float) value); } else if (value.getClass() == Double.class) { - ps.setDouble(iii, (Double)value); + ps.setDouble(iii, (Double) value); } else if (value.getClass() == Boolean.class) { - ps.setBoolean(iii, (Boolean)value); + ps.setBoolean(iii, (Boolean) value); } else if (value.getClass() == Boolean.class) { - ps.setBoolean(iii, (Boolean)value); + ps.setBoolean(iii, (Boolean) value); } else if (value.getClass() == Timestamp.class) { - ps.setTimestamp(iii, (Timestamp)value); + ps.setTimestamp(iii, (Timestamp) value); } else if (value.getClass() == Date.class) { - ps.setDate(iii, (Date)value); + ps.setDate(iii, (Date) value); } else { throw new Exception("Not manage type ==> need to add it ..."); } } - @Deprecated - public static T getWith(Class clazz, String key, String value) throws Exception { - return getWhere(clazz, List.of(new WhereCondition(key, "=", value)), false); + + public static T getWhere(final Class clazz, final QuerryItem condition) throws Exception { + return getWhere(clazz, condition, false); } - // keep the simple ... - public static T getWhere(Class clazz, String key, String operator, Object value, boolean full ) throws Exception { - return getWhere(clazz, List.of(new WhereCondition(key, operator, value)), full); - } - @Deprecated - public static T getWhere(Class clazz, String key, String operator, Object value ) throws Exception { - return getWhere(clazz, List.of(new WhereCondition(key, operator, value)), false); - } - @Deprecated - public static T getWhere(Class clazz, String key, String operator, Object value, String key2, String operator2, Object value2 ) throws Exception { - return getWhere(clazz, - List.of( - new WhereCondition(key, operator, value), - new WhereCondition(key2, operator2, value2) - ), false); - } - @Deprecated - public static T getWhere(Class clazz, String key, String operator, Object value, String key2, String operator2, Object value2, boolean full ) throws Exception { - return getWhere(clazz, - List.of( - new WhereCondition(key, operator, value), - new WhereCondition(key2, operator2, value2) - ), full); - } - - public static T getWhere(Class clazz, List condition, boolean full ) throws Exception { - List values = getsWhere(clazz, condition, full, 1); - if (values.size() == 0) { - return null; - } - return values.get(0); - } - @Deprecated - public static List getsWhere(Class clazz, String key, String operator, Object value ) throws Exception { - return getsWhere(clazz, List.of(new WhereCondition(key, operator, value)), null, false, null); - } - @Deprecated - public static List getsWhere(Class clazz, String key, String operator, Object value, boolean full ) throws Exception { - return getsWhere(clazz, List.of(new WhereCondition(key, operator, value)), null, full, null); + public static T getWhere(final Class clazz, final QuerryItem condition, final boolean full) throws Exception { + final List values = getsWhere(clazz, condition, full, 1); + if (values.size() == 0) { + return null; + } + return values.get(0); } - public static List getsWhere(Class clazz, List condition) throws Exception { + public static List getsWhere(final Class clazz, final QuerryItem condition) throws Exception { return getsWhere(clazz, condition, null, false, null); } - public static List getsWhere(Class clazz, List condition, boolean full ) throws Exception { + + public static List getsWhere(final Class clazz, final QuerryItem condition, final boolean full) throws Exception { return getsWhere(clazz, condition, null, full, null); } - public static List getsWhere(Class clazz, List condition, boolean full, Integer linit) throws Exception { + + public static List getsWhere(final Class clazz, final QuerryItem condition, final boolean full, final Integer linit) throws Exception { return getsWhere(clazz, condition, null, full, linit); } - public static void whereAppendQuery(StringBuilder query, String tableName, List condition, boolean exclude_deleted) throws ExceptionDBInterface { + + public static void whereAppendQuery(final StringBuilder querry, final String tableName, final QuerryItem condition, final boolean exclude_deleted) throws ExceptionDBInterface { // Check if we have a condition to generate - if (condition == null || condition.size() == 0) { + if (condition == null) { + if (exclude_deleted) { + querry.append(" WHERE "); + querry.append(tableName); + querry.append(".deleted = false "); + } return; } - query.append(" WHERE "); - boolean first = true; - for (WhereCondition elem : condition) { - if (first) { - first = false; - } else { - query.append(" AND "); - } - query.append(tableName); - query.append("."); - query.append(elem.key()); - query.append(" "); - query.append(elem.comparator()); - query.append(" ?"); - } - if (exclude_deleted) { - if (!first) { - query.append(" AND "); - } - query.append(tableName); - query.append(".deleted = false "); - } + querry.append(" WHERE ("); + condition.generateQuerry(querry, tableName); + + querry.append(") "); + if (exclude_deleted) { + querry.append("AND "); + querry.append(tableName); + querry.append(".deleted = false "); + } } - public static void whereInjectValue(PreparedStatement ps, List condition) throws Exception { + + public static void whereInjectValue(final PreparedStatement ps, final QuerryItem condition) throws Exception { // Check if we have a condition to generate - if (condition == null || condition.size() == 0) { + if (condition == null) { return; } int iii = 1; - for (WhereCondition elem : condition) { - addElement(ps, elem.Value(), iii++); - } + iii = condition.injectQuerry(ps, iii); } - public static int executeSimpleQuerry(String querry, boolean root) throws SQLException, IOException { - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); - Statement stmt = entry.connection.createStatement(); - return stmt.executeUpdate(querry); + + public static int executeSimpleQuerry(final String querry, final boolean root) throws SQLException, IOException { + final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); + final Statement stmt = entry.connection.createStatement(); + return stmt.executeUpdate(querry); } - - public static int executeSimpleQuerry(String querry) throws SQLException, IOException { + + public static int executeSimpleQuerry(final String querry) throws SQLException, IOException { return executeSimpleQuerry(querry, false); } - public static boolean executeQuerry(String querry, boolean root) throws SQLException, IOException { - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); - Statement stmt = entry.connection.createStatement(); - return stmt.execute(querry); + + public static boolean executeQuerry(final String querry, final boolean root) throws SQLException, IOException { + final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig, root); + final Statement stmt = entry.connection.createStatement(); + return stmt.execute(querry); } - - public static boolean executeQuerry(String querry) throws SQLException, IOException { + + public static boolean executeQuerry(final String querry) throws SQLException, IOException { return executeQuerry(querry, false); } - - @SuppressWarnings("unchecked") - public static List getsWhere(Class clazz, List condition, String orderBy, boolean full, Integer linit) throws Exception { - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - List outs = new ArrayList<>(); - // real add in the BDD: - try { - String tableName = getTableName(clazz); - //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - StringBuilder query = new StringBuilder(); - query.append("SELECT "); - //query.append(tableName); - //query.append(" SET "); - boolean firstField = true; - int count = 0; - boolean hasDeleted = false; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric != ModelLink.NONE) { + @SuppressWarnings("unchecked") + public static List getsWhere(final Class clazz, final QuerryItem condition, final String orderBy, final boolean full, final Integer linit) throws Exception { + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final List outs = new ArrayList<>(); + // real add in the BDD: + try { + final String tableName = AnnotationTools.getTableName(clazz); + //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final StringBuilder querry = new StringBuilder(); + querry.append("SELECT "); + //querry.append(tableName); + //querry.append(" SET "); + + boolean firstField = true; + int count = 0; + boolean hasDeleted = false; + 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; } - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null) { + continue; + } + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; if (!full && createTime) { continue; } if (!hasDeleted) { hasDeleted = elem.getDeclaredAnnotationsByType(SQLDeleted.class).length != 0; } - String name = elem.getName(); - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + final String name = elem.getName(); + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; if (!full && updateTime) { continue; } count++; if (firstField) { - firstField = false; + firstField = false; } else { - query.append(","); + querry.append(","); } - query.append(" "); - query.append(tableName); - query.append("."); - - query.append(name); - } - query.append(" FROM `"); - query.append(tableName); - query.append("` "); - whereAppendQuery(query, tableName, condition, firstField); - if (orderBy != null && orderBy.length() >= 1) { - query.append(" ORDER BY "); - //query.append(tableName); - //query.append("."); - query.append(orderBy); - } - if (linit != null && linit >= 1) { - query.append(" LIMIT " + linit); - } - /* - query.append(" AND "); - query.append(tableName); - query.append(".deleted = false "); - */ - firstField = true; - //logger.debug("generate the query: '{}'", query.toString()); - // prepare the request: - PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); - whereInjectValue(ps, condition); - // execute the request - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - Object data = clazz.getConstructors()[0].newInstance(); - count = 1; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric != ModelLink.NONE) { - continue; - } - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; - if (!full && createTime) { - continue; - } - //String name = elem.getName(); - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; - if (!full && updateTime) { - continue; - } - setValueFromDb(elem.getType(), data, count, elem, rs); - count++; - } - T out = (T)data; - outs.add(out); - } + querry.append(" "); + querry.append(tableName); + querry.append("."); - } catch (SQLException ex) { - ex.printStackTrace(); - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - entry.close(); - entry = null; - } - return outs; + querry.append(name); + } + querry.append(" FROM `"); + querry.append(tableName); + querry.append("` "); + whereAppendQuery(querry, tableName, condition, firstField); + if (orderBy != null && orderBy.length() >= 1) { + querry.append(" ORDER BY "); + //querry.append(tableName); + //querry.append("."); + querry.append(orderBy); + } + if (linit != null && linit >= 1) { + querry.append(" LIMIT " + linit); + } + firstField = true; + LOGGER.debug("generate the querry: '{}'", querry.toString()); + // prepare the request: + final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); + whereInjectValue(ps, condition); + // execute the request + final ResultSet rs = ps.executeQuery(); + while (rs.next()) { + final Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + 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 SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null) { + continue; + } + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; + if (!full && createTime) { + continue; + } + //String name = elem.getName(); + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; + if (!full && updateTime) { + continue; + } + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } + final T out = (T) data; + outs.add(out); + } + + } catch (final SQLException ex) { + ex.printStackTrace(); + } catch (final Exception ex) { + ex.printStackTrace(); + } finally { + entry.close(); + entry = null; + } + return outs; } - - public static T get(Class clazz, long id) throws Exception { - Field primaryKeyField = null; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; - if (primaryKey) { + + public static T get(final Class clazz, final long id) throws Exception { + Field primaryKeyField = null; + 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; + } + if (AnnotationTools.isPrimaryKey(elem)) { primaryKeyField = elem; } - } + } if (primaryKeyField != null) { - return SqlWrapper.getWhere(clazz, List.of(new WhereCondition(primaryKeyField.getName(), "=", id)), false); + return SqlWrapper.getWhere(clazz, new QuerryCondition(primaryKeyField.getName(), "=", id), false); } throw new Exception("Missing primary Key..."); } - - private enum StateLoad { - DISABLE, - NORMAL, - ARRAY - }; - + public static String getCurrentTimeStamp() { - return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); } - - public static List gets(Class clazz, boolean full) throws Exception { + + public static List gets(final Class clazz, final boolean full) throws Exception { LOGGER.debug("request get {} start @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - List out = new ArrayList<>(); - // real add in the BDD: - try { - String tableName = getTableName(clazz); - //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - StringBuilder query = new StringBuilder(); - query.append("SELECT "); - boolean firstField = true; - int count = 0; - StateLoad[] autoClasify = new StateLoad[clazz.getFields().length]; - int indexAutoClasify = 0; - boolean hasDeleted = false; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final List out = new ArrayList<>(); + // real add in the BDD: + try { + final String tableName = AnnotationTools.getTableName(clazz); + //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final StringBuilder querry = new StringBuilder(); + querry.append("SELECT "); + boolean firstField = true; + int count = 0; + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! A revoir, il faut faire une liste dynamique qui dépend des add_ons.... + //StateLoad[] autoClasify = new StateLoad[clazz.getFields().length]; + final List autoClasify = new ArrayList<>(); + int indexAutoClasify = 0; + boolean hasDeleted = false; + 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 boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; if (!full && notRead) { - autoClasify[indexAutoClasify++] = StateLoad.DISABLE; + autoClasify.add(StateLoad.DISABLE); continue; } if (!hasDeleted) { hasDeleted = elem.getDeclaredAnnotationsByType(SQLDeleted.class).length != 0; } - String name = elem.getName(); - count++; + final String name = elem.getName(); if (firstField) { - firstField = false; + firstField = false; } else { - query.append(","); + querry.append(","); } - - - ModelLink linkGeneric = getLinkMode(elem); - if (linkGeneric == ModelLink.EXTERNAL) { - autoClasify[indexAutoClasify++] = StateLoad.ARRAY; - String localName = name; - if (name.endsWith("s")) { - localName = name.substring(0, name.length()-1); + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null) { + count += addOn.generateQuerry(tableName, elem, querry, name, autoClasify); + } else { + count++; + autoClasify.add(StateLoad.NORMAL); + querry.append(" "); + querry.append(tableName); + querry.append("."); + querry.append(name); + } + } + querry.append(" FROM `"); + querry.append(tableName); + querry.append("` "); + if (hasDeleted) { + querry.append(" WHERE "); + //querry.append(tableName); + //querry.append("."); + //querry.append(primaryKeyField.getName()); + //querry.append(" = ?"); + //querry.append(" AND "); + querry.append(tableName); + querry.append(".deleted = false "); + } + firstField = true; + LOGGER.debug("generate the querry: '{}'", querry.toString()); + LOGGER.debug("request get {} prepare @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); + // prepare the request: + final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); + + LOGGER.debug("request get {} querry @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); + // execute the request + final ResultSet rs = ps.executeQuery(); + LOGGER.debug("request get {} transform @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); + + while (rs.next()) { + indexAutoClasify = 0; + final Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (final Field elem : clazz.getFields()) { + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; } - String tmpVariable = "tmp_" + Integer.toString(count); - query.append(" (SELECT GROUP_CONCAT("); - query.append(tmpVariable); - query.append("."); - query.append(localName); - query.append("_id SEPARATOR '-') FROM "); - query.append(tableName); - query.append("_link_"); - query.append(localName); - query.append(" "); - query.append(tmpVariable); - query.append(" WHERE "); - query.append(tmpVariable); - query.append(".deleted = false AND "); - query.append(tableName); - query.append(".id = "); - query.append(tmpVariable); - query.append("."); - query.append(tableName); - query.append("_id GROUP BY "); - query.append(tmpVariable); - query.append("."); - query.append(tableName); - query.append("_id ) AS "); - query.append(name); - query.append(" "); /* - " (SELECT GROUP_CONCAT(tmp.data_id SEPARATOR '-')" + - " FROM cover_link_node tmp" + - " WHERE tmp.deleted = false" + - " AND node.id = tmp.node_id" + - " GROUP BY tmp.node_id) AS covers" + - */ - } else { - if (linkGeneric == ModelLink.NONE) { - autoClasify[indexAutoClasify++] = StateLoad.NORMAL; - } else { - autoClasify[indexAutoClasify++] = StateLoad.ARRAY; + boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + */ + final boolean notRead = autoClasify.get(indexAutoClasify) == StateLoad.DISABLE; + if (!full && notRead) { + indexAutoClasify++; + continue; } - query.append(" "); - query.append(tableName); - query.append("."); - query.append(name); + //String name = elem.getName(); + //boolean linkGeneric = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class).length != 0; + + final SqlWrapperAddOn addOn = findAddOnforField(elem); + if (addOn != null) { + count += addOn.fillFromQuerry(rs, elem, data, count); + } else { + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } + indexAutoClasify++; } - } - query.append(" FROM `"); - query.append(tableName); - query.append("` "); - if (hasDeleted) { - query.append(" WHERE "); - //query.append(tableName); - //query.append("."); - //query.append(primaryKeyField.getName()); - //query.append(" = ?"); - //query.append(" AND "); - query.append(tableName); - query.append(".deleted = false "); - } - firstField = true; - LOGGER.debug("generate the querry: '{}'", query.toString()); - LOGGER.debug("request get {} prepare @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); - // prepare the request: - PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + //logger.debug("Read: {}", (T)data); + out.add((T) data); + } - LOGGER.debug("request get {} query @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); - // execute the request - ResultSet rs = ps.executeQuery(); - LOGGER.debug("request get {} transform @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); - - while (rs.next()) { - indexAutoClasify = 0; - Object data = clazz.getConstructors()[0].newInstance(); - count = 1; - for (Field elem : clazz.getFields()) { - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - /* - boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; - */ - boolean notRead = autoClasify[indexAutoClasify] == StateLoad.DISABLE; - if (!full && notRead) { - indexAutoClasify++; - continue; - } - //String name = elem.getName(); - //boolean linkGeneric = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class).length != 0; - boolean linkGeneric = autoClasify[indexAutoClasify] == StateLoad.ARRAY; - if (linkGeneric) { - List idList = getListOfIds(rs, count); - elem.set(data, idList); - } else { - setValueFromDb(elem.getType(), data, count, elem, rs); - } - indexAutoClasify++; - count++; - } - //logger.debug("Read: {}", (T)data); - out.add((T)data); - } + LOGGER.debug("request get {} ready @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); - LOGGER.debug("request get {} ready @{}", clazz.getCanonicalName(), getCurrentTimeStamp()); - - } catch (SQLException ex) { - ex.printStackTrace(); - } finally { - entry.close(); - entry = null; - } - return out; + } catch (final SQLException ex) { + ex.printStackTrace(); + } finally { + entry.close(); + entry = null; + } + return out; } - public static void addLink(Class clazz, long localKey, String table, long remoteKey) throws Exception { - String tableName = getTableName(clazz); - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - long uniqueSQLID = -1; - // real add in the BDD: - try { - // prepare the request: - String query = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + - " VALUES (" + getDBNow() + ", " + getDBNow() + ", ?, ?)"; - PreparedStatement ps = entry.connection.prepareStatement(query, - Statement.RETURN_GENERATED_KEYS); - int iii = 1; - ps.setLong(iii++, localKey); - ps.setLong(iii++, remoteKey); - // execute the request - int affectedRows = ps.executeUpdate(); - if (affectedRows == 0) { - throw new SQLException("Creating data failed, no rows affected."); - } - // retrieve uid inserted - try (ResultSet generatedKeys = ps.getGeneratedKeys()) { - if (generatedKeys.next()) { - uniqueSQLID = generatedKeys.getLong(1); - } else { - throw new SQLException("Creating user failed, no ID obtained (1)."); - } - } catch (Exception ex) { - LOGGER.debug("Can not get the UID key inserted ... "); - ex.printStackTrace(); - throw new SQLException("Creating user failed, no ID obtained (2)."); - } - } catch (SQLException ex) { - ex.printStackTrace(); - throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); - } finally { - entry.close(); - entry = null; - } - } - public static void removeLink(Class clazz, long localKey, String table, long remoteKey) throws Exception { - String tableName = getTableName(clazz); - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - String query = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=" + getDBNow() + ", `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table + "_id` = ?"; - try { - PreparedStatement ps = entry.connection.prepareStatement(query); - int iii = 1; - ps.setLong(iii++, localKey); - ps.setLong(iii++, remoteKey); - ps.executeUpdate(); - } catch (SQLException ex) { - ex.printStackTrace(); - throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); - } finally { - entry.close(); - entry = null; - } - } - - /** - * extract a list of "-" separated element from a SQL input data. - * @param rs Result Set of the BDD - * @param iii Id in the result set - * @return The list of Long value - * @throws SQLException if an error is generated in the sql request. - */ - protected static List getListOfIds(ResultSet rs, int iii) throws SQLException { - String trackString = rs.getString(iii); - if (rs.wasNull()) { - return null; - } - List out = new ArrayList<>(); - String[] elements = trackString.split("-"); - for (String elem : elements) { - Long tmp = Long.parseLong(elem); - out.add(tmp); - } - return out; - } - /** - * Convert the list if external id in a string '-' separated - * @param ids List of value (null are removed) - * @return '-' string separated - */ - protected static String getStringOfIds(List ids) { - List tmp = new ArrayList<>(); - for (Long elem : ids) { - tmp.add(elem); - } - return tmp.stream().map(x->String.valueOf(x)).collect(Collectors.joining("-")); - } - - - public static void delete(Class clazz, long id) throws Exception { + public static void delete(final Class clazz, final long id) throws Exception { // TODO: I am not sure this is a real good idea. } - public static int setDelete(Class clazz, long id) throws Exception { - return setDeleteWhere(clazz, List.of( - new WhereCondition("id", "=", id) - )); + + public static int setDelete(final Class clazz, final long id) throws Exception { + return setDeleteWhere(clazz, new QuerryCondition("id", "=", id)); } + public static String getDBNow() { if (!ConfigBaseVariable.getDBType().equals("sqlite")) { return "now(3)"; } return "DATE()"; } - public static int setDeleteWhere(Class clazz, List condition) throws Exception { - String tableName = getTableName(clazz); - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - StringBuilder query = new StringBuilder(); - query.append("UPDATE `"); - query.append(tableName); - query.append("` SET `modify_date`="); - query.append(getDBNow()); - query.append(", `deleted`=true "); - whereAppendQuery(query, tableName, condition, false); - try { - PreparedStatement ps = entry.connection.prepareStatement(query.toString()); - whereInjectValue(ps, condition); - int affectedRows = ps.executeUpdate(); - return affectedRows; - } finally { - entry.close(); - entry = null; - } - } - - - public static int unsetDelete(Class clazz, long id) throws Exception { - return unsetDeleteWhere(clazz, List.of( - new WhereCondition("id", "=", id) - )); - } - - public static int unsetDeleteWhere(Class clazz, List condition) throws Exception { - String tableName = getTableName(clazz); - DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); - StringBuilder query = new StringBuilder(); - query.append("UPDATE `"); - query.append(tableName); - query.append("` SET `modify_date`="); - query.append(getDBNow()); - query.append(", `deleted`=false "); - whereAppendQuery(query, tableName, condition, false); - try { - PreparedStatement ps = entry.connection.prepareStatement(query.toString()); - whereInjectValue(ps, condition); - int affectedRows = ps.executeUpdate(); - return affectedRows; - } finally { - entry.close(); - entry = null; - } + + public static int setDeleteWhere(final Class clazz, final QuerryItem condition) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final StringBuilder querry = new StringBuilder(); + querry.append("UPDATE `"); + querry.append(tableName); + querry.append("` SET `modify_date`="); + querry.append(getDBNow()); + querry.append(", `deleted`=true "); + whereAppendQuery(querry, tableName, condition, false); + try { + final PreparedStatement ps = entry.connection.prepareStatement(querry.toString()); + whereInjectValue(ps, condition); + final int affectedRows = ps.executeUpdate(); + return affectedRows; + } finally { + entry.close(); + entry = null; + } } - public static List createTable(Class clazz) throws Exception { + public static int unsetDelete(final Class clazz, final long id) throws Exception { + return unsetDeleteWhere(clazz, new QuerryCondition("id", "=", id)); + } + + public static int unsetDeleteWhere(final Class clazz, final QuerryItem condition) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final StringBuilder querry = new StringBuilder(); + querry.append("UPDATE `"); + querry.append(tableName); + querry.append("` SET `modify_date`="); + querry.append(getDBNow()); + querry.append(", `deleted`=false "); + whereAppendQuery(querry, tableName, condition, false); + try { + final PreparedStatement ps = entry.connection.prepareStatement(querry.toString()); + whereInjectValue(ps, condition); + final int affectedRows = ps.executeUpdate(); + return affectedRows; + } finally { + entry.close(); + entry = null; + } + } + + public static List createTable(final Class clazz) throws Exception { return createTable(clazz, true); } - public static List createTable(Class clazz, boolean createDrop) throws Exception { - String tableName = getTableName(clazz); - boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; - List outList = new ArrayList<>(); - StringBuilder out = new StringBuilder(); + + public static void createTablesSpecificType(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List ListOtherTables, final boolean createIfNotExist, + final boolean createDrop, final int fieldId, final Class classModel) throws Exception { + final String name = elem.getName(); + final Integer limitSize = AnnotationTools.getLimitSize(elem); + final boolean notNull = AnnotationTools.getNotNull(elem); + + final boolean primaryKey = AnnotationTools.isPrimaryKey(elem); + final GenerationType strategy = AnnotationTools.getStrategy(elem); + + final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; + final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; + final String comment = AnnotationTools.getComment(elem); + final String defaultValue = AnnotationTools.getDefault(elem); + + if (fieldId == 0) { + mainTableBuilder.append("\n\t\t`"); + } else { + mainTableBuilder.append(",\n\t\t`"); + } + mainTableBuilder.append(name); + mainTableBuilder.append("` "); + String typeValue = null; + typeValue = convertTypeInSQL(classModel); + if (typeValue.equals("text") && !ConfigBaseVariable.getDBType().equals("sqlite")) { + if (limitSize != null) { + mainTableBuilder.append("varchar("); + mainTableBuilder.append(limitSize); + mainTableBuilder.append(")"); + } else { + mainTableBuilder.append("text"); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append(" CHARACTER SET utf8"); + } + } + } else { + mainTableBuilder.append(typeValue); + } + mainTableBuilder.append(" "); + if (notNull) { + if (!primaryKey || !ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("NOT NULL "); + } + if (defaultValue == null) { + if (updateTime || createTime) { + mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP"); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("(3)"); + } + mainTableBuilder.append(" "); + } + if (updateTime) { + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP"); + mainTableBuilder.append("(3)"); + } + mainTableBuilder.append(" "); + } + } else { + mainTableBuilder.append("DEFAULT "); + if ("CURRENT_TIMESTAMP(3)".equals(defaultValue) && ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("CURRENT_TIMESTAMP"); + } else { + mainTableBuilder.append(defaultValue); + } + mainTableBuilder.append(" "); + if (updateTime) { + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP"); + mainTableBuilder.append("(3)"); + } + mainTableBuilder.append(" "); + } + } + } else if (defaultValue == null) { + if (updateTime || createTime) { + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP "); + } else { + mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP(3) "); + } + } else { + mainTableBuilder.append("DEFAULT NULL "); + } + } else { + mainTableBuilder.append("DEFAULT "); + mainTableBuilder.append(defaultValue); + mainTableBuilder.append(" "); + + } + if (primaryKey && ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("PRIMARY KEY "); + + } + if (strategy == GenerationType.IDENTITY) { + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("AUTO_INCREMENT "); + } else { + mainTableBuilder.append("AUTOINCREMENT "); + } + } else if (strategy != null) { + throw new Exception("Can not generate a stategy different of IDENTITY"); + } + + if (comment != null && !ConfigBaseVariable.getDBType().equals("sqlite")) { + mainTableBuilder.append("COMMENT '"); + mainTableBuilder.append(comment.replace('\'', '\'')); + mainTableBuilder.append("' "); + } + } + + public static List createTable(final Class clazz, final boolean createDrop) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + final List outList = new ArrayList<>(); + final StringBuilder out = new StringBuilder(); // Drop Table if (createIfNotExist && createDrop) { - StringBuilder tableTmp = new StringBuilder(); + final StringBuilder tableTmp = new StringBuilder(); tableTmp.append("DROP TABLE IF EXISTS `"); tableTmp.append(tableName); tableTmp.append("`;"); @@ -1299,256 +1220,53 @@ public class SqlWrapper { out.append("CREATE TABLE `"); out.append(tableName); out.append("` ("); - boolean firstField = true; + int fieldId = 0; LOGGER.debug("===> TABLE `{}`", tableName); - String primaryKeyValue = null; - for (Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } + final List primaryKeys = new ArrayList<>(); - String name = elem.getName(); - Integer limitSize = getLimitSize(elem); - boolean notNull = elem.getDeclaredAnnotationsByType(SQLNotNull.class).length != 0; - boolean autoIncrement = elem.getDeclaredAnnotationsByType(SQLAutoIncrement.class).length != 0; - - boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; - //boolean sqlNotRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; - boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; - boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; - ModelLink linkGeneric = getLinkMode(elem); - String comment = getComment(elem); - String defaultValue = getDefault(elem); - //logger.debug(" ==> elem `" + name + "` primaryKey=" + primaryKey + " linkGeneric=" + linkGeneric); - - - if (primaryKey) { - primaryKeyValue = name; + for (final Field elem : clazz.getFields()) { + // DEtect the primary key (support only one primary key right now... + if (AnnotationTools.isPrimaryKey(elem)) { + primaryKeys.add(elem.getName()); } - // special case with external link table: - if (linkGeneric == ModelLink.EXTERNAL) { - String localName = name; - if (name.endsWith("s")) { - localName = name.substring(0, name.length()-1); - } - if (createIfNotExist && createDrop) { - StringBuilder tableTmp = new StringBuilder(); - tableTmp.append("DROP TABLE IF EXISTS `"); - tableTmp.append(tableName); - tableTmp.append("_link_"); - tableTmp.append(localName); - tableTmp.append("`;"); - outList.add(tableTmp.toString()); - } - StringBuilder otherTable = new StringBuilder(); - otherTable.append("CREATE TABLE `"); - otherTable.append(tableName); - otherTable.append("_link_"); - otherTable.append(localName); - otherTable.append("`(\n"); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - otherTable.append("\t\t`id` bigint NOT NULL AUTO_INCREMENT,\n"); - otherTable.append("\t\t`deleted` tinyint(1) NOT NULL DEFAULT '0',\n"); - otherTable.append("\t\t`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n"); - otherTable.append("\t\t`modify_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n"); + } + + 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; + } + if (isAddOnField(elem)) { + final SqlWrapperAddOn addOn = findAddOnforField(elem); + LOGGER.info("Create type for: {} ==> {} (ADD-ON)", elem.getName(), elem.getType()); + if (addOn != null) { + addOn.createTables(tableName, elem, out, outList, createIfNotExist, createDrop, fieldId); } else { - otherTable.append("\t\t`id` INTEGER PRIMARY KEY AUTOINCREMENT,\n"); - otherTable.append("\t\t`deleted` INTEGER NOT NULL DEFAULT '0',\n"); - otherTable.append("\t\t`create_date` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n"); - otherTable.append("\t\t`modify_date` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n"); + throw new Exception("Element matked as add-on but add-on does not loaded: table:" + tableName + " field name=" + elem.getName() + " type=" + elem.getType()); } - otherTable.append("\t\t`"); - otherTable.append(tableName); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - otherTable.append("_id` bigint NOT NULL,\n"); - } else { - otherTable.append("_id` INTEGER NOT NULL,\n"); - } - otherTable.append("\t\t`"); - otherTable.append(localName); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - otherTable.append("_id` bigint NOT NULL\n"); - } else { - otherTable.append("_id` INTEGER NOT NULL\n"); - } - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - otherTable.append("\t, PRIMARY KEY (`id`)\n"); - } - otherTable.append("\t)"); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - otherTable.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n"); - } - otherTable.append(";"); - outList.add(otherTable.toString()); } else { - if (firstField) { - out.append("\n\t\t`"); - firstField = false; - } else { - out.append(",\n\t\t`"); + LOGGER.info("Create type for: {} ==> {}", elem.getName(), elem.getType()); + SqlWrapper.createTablesSpecificType(tableName, elem, out, outList, createIfNotExist, createDrop, fieldId, elem.getType()); + } + fieldId++; + } + if (primaryKeys.size() != 0 && !ConfigBaseVariable.getDBType().equals("sqlite")) { + out.append(",\n\tPRIMARY KEY (`"); + for (int iii = 0; iii < primaryKeys.size(); iii++) { + if (iii != 0) { + out.append(","); } - out.append(name); - out.append("` "); - String typeValue = null; - if (linkGeneric == ModelLink.INTERNAL) { - typeValue = convertTypeInSQL(String.class); - out.append(typeValue); - } else { - typeValue = convertTypeInSQL(elem.getType()); - if (typeValue.equals("text") && !ConfigBaseVariable.getDBType().equals("sqlite")) { - if (limitSize != null) { - out.append("varchar("); - out.append(limitSize); - out.append(")"); - } else { - out.append("text"); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append(" CHARACTER SET utf8"); - } - } - } else { - out.append(typeValue); - } - } - out.append(" "); - if (notNull) { - if (!name.equals(primaryKeyValue) || !ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("NOT NULL "); - } - if (defaultValue == null) { - if (updateTime || createTime) { - out.append("DEFAULT CURRENT_TIMESTAMP"); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("(3)"); - } - out.append(" "); - } - if (updateTime) { - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("ON UPDATE CURRENT_TIMESTAMP"); - out.append("(3)"); - } - out.append(" "); - } - } else { - out.append("DEFAULT "); - if ("CURRENT_TIMESTAMP(3)".equals(defaultValue) && ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("CURRENT_TIMESTAMP"); - } else { - out.append(defaultValue); - } - out.append(" "); - if (updateTime) { - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("ON UPDATE CURRENT_TIMESTAMP"); - out.append("(3)"); - } - out.append(" "); - } - } - } else if (defaultValue == null) { - if (updateTime || createTime) { - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("DEFAULT CURRENT_TIMESTAMP "); - }else { - out.append("DEFAULT CURRENT_TIMESTAMP(3) "); - } - } else { - out.append("DEFAULT NULL "); - } - } else { - out.append("DEFAULT "); - out.append(defaultValue); - out.append(" "); - - } - if (name.equals(primaryKeyValue) && ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("PRIMARY KEY "); - - } - if (autoIncrement) { - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("AUTO_INCREMENT "); - } else { - out.append("AUTOINCREMENT "); - } - } - - if (comment != null && !ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append("COMMENT '"); - out.append(comment.replaceAll("'", "\'")); - out.append("' "); - } - } - } - if (primaryKeyValue != null && !ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append(",\n\tPRIMARY KEY (`"); - out.append(primaryKeyValue); - out.append("`)"); - } - out.append("\n\t)"); - if (!ConfigBaseVariable.getDBType().equals("sqlite")) { - out.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci"); - } - out.append(";"); - outList.add( out.toString()); - return outList; + out.append(primaryKeys.get(iii)); + } + out.append("`)"); + } + out.append("\n\t)"); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + out.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci"); + } + out.append(";"); + outList.add(out.toString()); + return outList; } - - - public static String getTableName(final Class element) throws Exception { - final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLTableName.class); - if (annotation.length == 0) { - return null; - } - if (annotation.length > 1) { - throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); - } - final String tmp = ((SQLTableName) annotation[0]).value(); - if (tmp == null) { - return null; - } - return tmp; - } - public static String getComment(final Field element) throws Exception { - final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLComment.class); - if (annotation.length == 0) { - return null; - } - if (annotation.length > 1) { - throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); - } - final String tmp = ((SQLComment) annotation[0]).value(); - if (tmp == null) { - return null; - } - return tmp; - } - public static String getDefault(final Field element) throws Exception { - final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLDefault.class); - if (annotation.length == 0) { - return null; - } - if (annotation.length > 1) { - throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); - } - final String tmp = ((SQLDefault) annotation[0]).value(); - if (tmp == null) { - return null; - } - return tmp; - } - public static Integer getLimitSize(final Field element) throws Exception { - final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLLimitSize.class); - if (annotation.length == 0) { - return null; - } - if (annotation.length > 1) { - throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); - } - return ((SQLLimitSize) annotation[0]).value(); - } - } \ No newline at end of file diff --git a/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java b/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java index 35ad376..f35a266 100644 --- a/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java +++ b/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java @@ -1,6 +1,10 @@ package org.kar.archidata.sqlWrapper; import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; public interface SqlWrapperAddOn { /** @@ -8,12 +12,14 @@ public interface SqlWrapperAddOn { * @return The annotation class */ Class getAnnotationClass(); + /** * Get the SQL type that is needed to declare for the specific Field Type. * @param elem Field to declare. * @return SQL type to create. */ String getSQLFieldType(Field elem); + /** * Check if the field is manage by the local add-on * @param elem Field to inspect. @@ -21,4 +27,17 @@ public interface SqlWrapperAddOn { */ boolean isCompatibleField(Field elem); + int insertData(PreparedStatement ps, Object data, int iii) throws SQLException; + + // External mean that the type of the object is absolutely not obvious... + boolean isExternal(); + + int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List autoClasify); + + int fillFromQuerry(ResultSet rs, Field elem, Object data, int count) throws SQLException, IllegalArgumentException, IllegalAccessException; + + boolean canUpdate(); + + void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception; + } diff --git a/src/org/kar/archidata/sqlWrapper/StateLoad.java b/src/org/kar/archidata/sqlWrapper/StateLoad.java new file mode 100644 index 0000000..08f6519 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/StateLoad.java @@ -0,0 +1,5 @@ +package org.kar.archidata.sqlWrapper; + +public enum StateLoad { + DISABLE, NORMAL, ARRAY +} \ No newline at end of file diff --git a/src/org/kar/archidata/sqlWrapper/WhereCondition.java b/src/org/kar/archidata/sqlWrapper/WhereCondition.java deleted file mode 100644 index 86f7f5b..0000000 --- a/src/org/kar/archidata/sqlWrapper/WhereCondition.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.kar.archidata.sqlWrapper; - -public record WhereCondition( - String key, - String comparator, - Object Value) { - -} diff --git a/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java b/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java new file mode 100644 index 0000000..c347f4d --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalForeinKeyAsList.java @@ -0,0 +1,115 @@ +package org.kar.archidata.sqlWrapper.addOn; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.kar.archidata.annotation.addOn.SQLTableExternalLink; +import org.kar.archidata.sqlWrapper.SqlWrapper; +import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; +import org.kar.archidata.sqlWrapper.StateLoad; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnSQLTableExternalLink.class); + + /** + * Convert the list if external id in a string '-' separated + * @param ids List of value (null are removed) + * @return '-' string separated + */ + protected static String getStringOfIds(List ids) { + List tmp = new ArrayList<>(); + for (Long elem : ids) { + tmp.add(elem); + } + return tmp.stream().map(x -> String.valueOf(x)).collect(Collectors.joining("-")); + } + + /** + * extract a list of "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the sql request. + */ + protected static List getListOfIds(ResultSet rs, int iii) throws SQLException { + String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + List out = new ArrayList<>(); + String[] elements = trackString.split("-"); + for (String elem : elements) { + Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + + @Override + public Class getAnnotationClass() { + return SQLTableExternalLink.class; + } + + public String getSQLFieldType(Field elem) { + return "STRING"; + } + + public boolean isCompatibleField(Field elem) { + SQLTableExternalLink decorators = elem.getDeclaredAnnotation(SQLTableExternalLink.class); + return decorators != null; + } + + public int insertData(PreparedStatement ps, Object data, int iii) throws SQLException { + if (data == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + @SuppressWarnings("unchecked") + String dataTmp = getStringOfIds((List) data); + ps.setString(iii++, dataTmp); + } + return iii++; + } + + @Override + public boolean isExternal() { + // TODO Auto-generated method stub + return false; + } + + @Override + public int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List autoClasify) { + autoClasify.add(StateLoad.ARRAY); + querry.append(" "); + querry.append(tableName); + querry.append("."); + querry.append(name); + return 1; + } + + @Override + public int fillFromQuerry(ResultSet rs, Field elem, Object data, int count) throws SQLException, IllegalArgumentException, IllegalAccessException { + List idList = getListOfIds(rs, count); + elem.set(data, idList); + return 1; + } + + @Override + public boolean canUpdate() { + return true; + } + + @Override + public void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception { + // TODO Auto-generated method stub + + SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, ListOtherTables, createIfNotExist, createDrop, fieldId, String.class); + } +} diff --git a/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalLink.java b/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalLink.java new file mode 100644 index 0000000..2285ef4 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/addOn/AddOnSQLTableExternalLink.java @@ -0,0 +1,265 @@ +package org.kar.archidata.sqlWrapper.addOn; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.annotation.addOn.SQLTableExternalLink; +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.sqlWrapper.SqlWrapper; +import org.kar.archidata.sqlWrapper.SqlWrapper.ExceptionDBInterface; +import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; +import org.kar.archidata.sqlWrapper.StateLoad; +import org.kar.archidata.util.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AddOnSQLTableExternalLink implements SqlWrapperAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnSQLTableExternalLink.class); + + /** + * Convert the list if external id in a string '-' separated + * @param ids List of value (null are removed) + * @return '-' string separated + */ + protected static String getStringOfIds(final List ids) { + final List tmp = new ArrayList<>(ids); + return tmp.stream().map(String::valueOf).collect(Collectors.joining("-")); + } + + /** + * extract a list of "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the sql request. + */ + protected static List getListOfIds(final ResultSet rs, final int iii) throws SQLException { + final String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + final List out = new ArrayList<>(); + final String[] elements = trackString.split("-"); + for (final String elem : elements) { + final Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + + @Override + public Class getAnnotationClass() { + return SQLTableExternalLink.class; + } + + @Override + public String getSQLFieldType(final Field elem) { + return "STRING"; + } + + @Override + public boolean isCompatibleField(final Field elem) { + final SQLTableExternalLink decorators = elem.getDeclaredAnnotation(SQLTableExternalLink.class); + return decorators != null; + } + + @Override + public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { + if (data == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + // TODO: we must check if the model of data in a list of Long ... !!!! + @SuppressWarnings("unchecked") + final String dataTmp = getStringOfIds((List) data); + ps.setString(iii++, dataTmp); + } + return iii++; + } + + @Override + public boolean isExternal() { + // TODO Auto-generated method stub + return false; + } + + @Override + public int generateQuerry(final String tableName, final Field elem, final StringBuilder querry, final String name, final List autoClasify) { + + autoClasify.add(StateLoad.ARRAY); + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length() - 1); + } + final String tmpVariable = "tmp_" + Integer.toString(autoClasify.size()); + querry.append(" (SELECT GROUP_CONCAT("); + querry.append(tmpVariable); + querry.append("."); + querry.append(localName); + querry.append("_id SEPARATOR '-') FROM "); + querry.append(tableName); + querry.append("_link_"); + querry.append(localName); + querry.append(" "); + querry.append(tmpVariable); + querry.append(" WHERE "); + querry.append(tmpVariable); + querry.append(".deleted = false AND "); + querry.append(tableName); + querry.append(".id = "); + querry.append(tmpVariable); + querry.append("."); + querry.append(tableName); + querry.append("_id GROUP BY "); + querry.append(tmpVariable); + querry.append("."); + querry.append(tableName); + querry.append("_id ) AS "); + querry.append(name); + querry.append(" "); + /* + " (SELECT GROUP_CONCAT(tmp.data_id SEPARATOR '-')" + + " FROM cover_link_node tmp" + + " WHERE tmp.deleted = false" + + " AND node.id = tmp.node_id" + + " GROUP BY tmp.node_id) AS covers" + + */ + return 1; + } + + @Override + public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count) throws SQLException, IllegalArgumentException, IllegalAccessException { + throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB"); + } + + @Override + public boolean canUpdate() { + return false; + } + + public static void addLink(final Class clazz, final long localKey, final String table, final long remoteKey) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + long uniqueSQLID = -1; + // real add in the BDD: + try { + // prepare the request: + final String querry = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + " VALUES (" + SqlWrapper.getDBNow() + ", " + + SqlWrapper.getDBNow() + ", ?, ?)"; + final PreparedStatement ps = entry.connection.prepareStatement(querry, Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setLong(iii++, localKey); + ps.setLong(iii++, remoteKey); + // execute the request + final int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating data failed, no rows affected."); + } + // retrieve uid inserted + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + uniqueSQLID = generatedKeys.getLong(1); + } else { + throw new SQLException("Creating user failed, no ID obtained (1)."); + } + } catch (final Exception ex) { + LOGGER.debug("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating user failed, no ID obtained (2)."); + } + } catch (final SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.close(); + entry = null; + } + } + + public static void removeLink(final Class clazz, final long localKey, final String table, final long remoteKey) throws Exception { + final String tableName = AnnotationTools.getTableName(clazz); + DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + final String querry = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=" + SqlWrapper.getDBNow() + ", `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table + + "_id` = ?"; + try { + final PreparedStatement ps = entry.connection.prepareStatement(querry); + int iii = 1; + ps.setLong(iii++, localKey); + ps.setLong(iii++, remoteKey); + ps.executeUpdate(); + } catch (final SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.close(); + entry = null; + } + } + + @Override + public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List ListOtherTables, final boolean createIfNotExist, + final boolean createDrop, final int fieldId) throws Exception { + final String name = elem.getName(); + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length() - 1); + } + if (createIfNotExist && createDrop) { + final StringBuilder tableTmp = new StringBuilder(); + tableTmp.append("DROP TABLE IF EXISTS `"); + tableTmp.append(tableName); + tableTmp.append("_link_"); + tableTmp.append(localName); + tableTmp.append("`;"); + ListOtherTables.add(tableTmp.toString()); + } + final StringBuilder otherTable = new StringBuilder(); + otherTable.append("CREATE TABLE `"); + otherTable.append(tableName); + otherTable.append("_link_"); + otherTable.append(localName); + otherTable.append("`(\n"); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + otherTable.append("\t\t`id` bigint NOT NULL AUTO_INCREMENT,\n"); + otherTable.append("\t\t`deleted` tinyint(1) NOT NULL DEFAULT '0',\n"); + otherTable.append("\t\t`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n"); + otherTable.append("\t\t`modify_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n"); + } else { + otherTable.append("\t\t`id` INTEGER PRIMARY KEY AUTOINCREMENT,\n"); + otherTable.append("\t\t`deleted` INTEGER NOT NULL DEFAULT '0',\n"); + otherTable.append("\t\t`create_date` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n"); + otherTable.append("\t\t`modify_date` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n"); + } + otherTable.append("\t\t`"); + otherTable.append(tableName); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + otherTable.append("_id` bigint NOT NULL,\n"); + } else { + otherTable.append("_id` INTEGER NOT NULL,\n"); + } + otherTable.append("\t\t`"); + otherTable.append(localName); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + otherTable.append("_id` bigint NOT NULL\n"); + } else { + otherTable.append("_id` INTEGER NOT NULL\n"); + } + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + otherTable.append("\t, PRIMARY KEY (`id`)\n"); + } + otherTable.append("\t)"); + if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + otherTable.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n"); + } + otherTable.append(";"); + ListOtherTables.add(otherTable.toString()); + } +} diff --git a/src/org/kar/archidata/sqlWrapper/addOn/ExternalLink.java b/src/org/kar/archidata/sqlWrapper/addOn/ExternalLink.java deleted file mode 100644 index c040a91..0000000 --- a/src/org/kar/archidata/sqlWrapper/addOn/ExternalLink.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.kar.archidata.sqlWrapper.addOn; - -import java.lang.reflect.Field; - -import org.kar.archidata.annotation.SQLTableLinkGeneric; -import org.kar.archidata.sqlWrapper.SqlWrapperAddOn; - -public class ExternalLink implements SqlWrapperAddOn { - - @Override - public Class getAnnotationClass() { - return SQLTableLinkGeneric.class; - } - public String getSQLFieldType(Field elem) { - return "STRING"; - } - public boolean isCompatibleField(Field elem) { - SQLTableLinkGeneric decorators = elem.getDeclaredAnnotation(SQLTableLinkGeneric.class); - return decorators != null; - } -} diff --git a/src/org/kar/archidata/util/ConfigBaseVariable.java b/src/org/kar/archidata/util/ConfigBaseVariable.java index 511c3d9..e3f1275 100644 --- a/src/org/kar/archidata/util/ConfigBaseVariable.java +++ b/src/org/kar/archidata/util/ConfigBaseVariable.java @@ -1,92 +1,94 @@ package org.kar.archidata.util; public class ConfigBaseVariable { - static public String tmpDataFolder = System.getenv("DATA_TMP_FOLDER"); - static public String dataFolder = System.getenv("DATA_FOLDER"); - static public String dbType = System.getenv("DB_TYPE"); - static public String dbHost = System.getenv("DB_HOST"); - static public String dbPort = System.getenv("DB_PORT"); - static public String dbUser = System.getenv("DB_USER"); - static public String dbKeepConnected = System.getenv("DB_KEEP_CONNECTED"); - static public String dbPassword = System.getenv("DB_PASSWORD"); - static public String bdDatabase = System.getenv("DB_DATABASE"); - static public String apiAdress = System.getenv("API_ADDRESS"); - static public String ssoAdress = System.getenv("SSO_ADDRESS"); - static public String ssoToken = System.getenv("SSO_TOKEN"); - - public static String getTmpDataFolder() { - if (tmpDataFolder == null) { - return "/application/data/tmp"; - } - return tmpDataFolder; - } - - public static String getMediaDataFolder() { - if (dataFolder == null) { - return "/application/data/media"; - } - return dataFolder; - } - - public static String getDBType() { - if (dbType == null) { - return "mysql"; - } - return dbType; - } - - public static String getDBHost() { - if (dbHost == null) { - return "localhost"; - } - return dbHost; - } - - public static String getDBPort() { - if (dbPort == null) { - return "3306"; - } - return dbPort; - } - - public static String getDBLogin() { - if (dbUser == null) { - return "root"; - } - return dbUser; - } - - public static String getDBPassword() { - if (dbPassword == null) { - return "base_db_password"; - } - return dbPassword; - } - - public static String getDBName() { - if (bdDatabase == null) { - return "unknown"; - } - return bdDatabase; - } - - public static boolean getDBKeepConnected() { - if (dbKeepConnected == null) { - return false; - } - return Boolean.parseBoolean(dbKeepConnected); - } - public static String getlocalAddress() { - if (apiAdress == null) { - return "http://0.0.0.0:80/api/"; - } - return apiAdress; - } - - public static String getSSOAddress() { - return ssoAdress; - } - public static String ssoToken() { - return ssoToken; - } + static public String tmpDataFolder = System.getenv("DATA_TMP_FOLDER"); + static public String dataFolder = System.getenv("DATA_FOLDER"); + static public String dbType = System.getenv("DB_TYPE"); + static public String dbHost = System.getenv("DB_HOST"); + static public String dbPort = System.getenv("DB_PORT"); + static public String dbUser = System.getenv("DB_USER"); + static public String dbKeepConnected = System.getenv("DB_KEEP_CONNECTED"); + static public String dbPassword = System.getenv("DB_PASSWORD"); + static public String bdDatabase = System.getenv("DB_DATABASE"); + static public String apiAdress = System.getenv("API_ADDRESS"); + static public String ssoAdress = System.getenv("SSO_ADDRESS"); + static public String ssoToken = System.getenv("SSO_TOKEN"); + + public static String getTmpDataFolder() { + if (tmpDataFolder == null) { + return "/application/data/tmp"; + } + return tmpDataFolder; + } + + public static String getMediaDataFolder() { + if (dataFolder == null) { + return "/application/data/media"; + } + return dataFolder; + } + + public static String getDBType() { + if (dbType == null) { + return "mysql"; + } + return dbType; + } + + public static String getDBHost() { + if (dbHost == null) { + return "localhost"; + } + return dbHost; + } + + public static String getDBPort() { + if (dbPort == null) { + return "3306"; + } + return dbPort; + } + + public static String getDBLogin() { + if (dbUser == null) { + return "root"; + } + return dbUser; + } + + public static String getDBPassword() { + if (dbPassword == null) { + return "base_db_password"; + } + return dbPassword; + } + + public static String getDBName() { + if (bdDatabase == null) { + return "unknown"; + } + return bdDatabase; + } + + public static boolean getDBKeepConnected() { + if (dbKeepConnected == null) { + return false; + } + return Boolean.parseBoolean(dbKeepConnected); + } + + public static String getlocalAddress() { + if (apiAdress == null) { + return "http://0.0.0.0:80/api/"; + } + return apiAdress; + } + + public static String getSSOAddress() { + return ssoAdress; + } + + public static String ssoToken() { + return ssoToken; + } } diff --git a/src/org/kar/archidata/util/DataTools.java b/src/org/kar/archidata/util/DataTools.java index 5954e4d..e7c5f37 100644 --- a/src/org/kar/archidata/util/DataTools.java +++ b/src/org/kar/archidata/util/DataTools.java @@ -11,283 +11,283 @@ import java.nio.file.StandardCopyOption; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; - -import jakarta.ws.rs.core.Response; +import java.util.List; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.kar.archidata.model.Data; +import org.kar.archidata.sqlWrapper.QuerryAnd; +import org.kar.archidata.sqlWrapper.QuerryCondition; import org.kar.archidata.sqlWrapper.SqlWrapper; +import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalLink; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.core.Response; + public class DataTools { - static final Logger logger = LoggerFactory.getLogger(DataTools.class); - - public final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks - public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks - /** - * Upload some data - */ - private static long tmpFolderId = 1; - - public static void createFolder(String path) throws IOException { - if (!Files.exists(java.nio.file.Path.of(path))) { - logger.info("Create folder: " + path); - Files.createDirectories(java.nio.file.Path.of(path)); - } - } - - public static long getTmpDataId() { - return tmpFolderId++; - } - public static String getTmpFileInData(long tmpFolderId) { - String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId; - try { - createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); - } catch (IOException e) { - e.printStackTrace(); - } - return filePath; - } - - public static String getTmpFolder() { - String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++; - try { - createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); - } catch (IOException e) { - e.printStackTrace(); - } - return filePath; - } - - public static String getFileData(long tmpFolderId) { - String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; - try { - createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); - } catch (IOException e) { - e.printStackTrace(); - } - return filePath; - } - - public static Data getWithSha512(String sha512) { - try { - return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512); + private final static Logger LOGGER = LoggerFactory.getLogger(DataTools.class); + + public final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks + public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks + /** + * Upload some data + */ + private static long tmpFolderId = 1; + + public static void createFolder(String path) throws IOException { + if (!Files.exists(java.nio.file.Path.of(path))) { + LOGGER.info("Create folder: " + path); + Files.createDirectories(java.nio.file.Path.of(path)); + } + } + + public static long getTmpDataId() { + return tmpFolderId++; + } + + public static String getTmpFileInData(long tmpFolderId) { + String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId; + try { + createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static String getTmpFolder() { + String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++; + try { + createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static String getFileData(long tmpFolderId) { + String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; + try { + createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static Data getWithSha512(String sha512) { + try { + return SqlWrapper.getWhere(Data.class, new QuerryCondition("sha512", "=", sha512)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - return null; - } - - public static Data getWithId(long id) { - try { - return SqlWrapper.getWhere(Data.class, "deleted", "=", false, "id", "=", id); + return null; + } + + public static Data getWithId(long id) { + try { + return SqlWrapper.getWhere(Data.class, new QuerryAnd(List.of(new QuerryCondition("deleted", "=", false), new QuerryCondition("id", "=", id)))); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - return null; - } - - public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException, SQLException { - // determine mime type: - String mimeType = ""; - String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); - switch (extension.toLowerCase()) { - case "jpg": - case "jpeg": - mimeType = "image/jpeg"; - break; - case "png": - mimeType = "image/png"; - break; - case "webp": - mimeType = "image/webp"; - break; - case "mka": - mimeType = "audio/x-matroska"; - break; - case "mkv": - mimeType = "video/x-matroska"; - break; - case "webm": - mimeType = "video/webm"; - break; - default: - throw new IOException("Can not find the mime type of data input: '" + extension + "'"); - } - String tmpPath = getTmpFileInData(tmpUID); - long fileSize = Files.size(Paths.get(tmpPath)); - Data out = new Data();; - try { - out.sha512 = sha512; - out.mimeType = mimeType; - out.size = fileSize; - out = SqlWrapper.insert(out); - } catch (SQLException ex) { - ex.printStackTrace(); - return null; - } catch (Exception e) { + return null; + } + + public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException, SQLException { + // determine mime type: + String mimeType = ""; + String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); + switch (extension.toLowerCase()) { + case "jpg": + case "jpeg": + mimeType = "image/jpeg"; + break; + case "png": + mimeType = "image/png"; + break; + case "webp": + mimeType = "image/webp"; + break; + case "mka": + mimeType = "audio/x-matroska"; + break; + case "mkv": + mimeType = "video/x-matroska"; + break; + case "webm": + mimeType = "video/webm"; + break; + default: + throw new IOException("Can not find the mime type of data input: '" + extension + "'"); + } + String tmpPath = getTmpFileInData(tmpUID); + long fileSize = Files.size(Paths.get(tmpPath)); + Data out = new Data(); + ; + try { + out.sha512 = sha512; + out.mimeType = mimeType; + out.size = fileSize; + out = SqlWrapper.insert(out); + } catch (SQLException ex) { + ex.printStackTrace(); + return null; + } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); - return null; + return null; } - - String mediaPath = getFileData(out.id); - logger.info("src = {}", tmpPath); - logger.info("dst = {}", mediaPath); - Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); - - logger.info("Move done"); - // all is done the file is correctly installed... - return out; - } - - public static void undelete(Long id) { + + String mediaPath = getFileData(out.id); + LOGGER.info("src = {}", tmpPath); + LOGGER.info("dst = {}", mediaPath); + Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); + + LOGGER.info("Move done"); + // all is done the file is correctly installed... + return out; + } + + public static void undelete(Long id) { try { SqlWrapper.unsetDelete(Data.class, id); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - } - - public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) { - return saveFile(uploadedInputStream, getTmpFileInData(idData)); - } - - public static void removeTemporaryFile(long idData) { - String filepath = getTmpFileInData(idData); - if (Files.exists(Paths.get(filepath))) { - try { - Files.delete(Paths.get(filepath)); - } catch (IOException e) { - logger.info("can not delete temporary file : {}", Paths.get(filepath)); - e.printStackTrace(); - } - } - } - - // save uploaded file to a defined location on the server - public static String saveFile(InputStream uploadedInputStream, String serverLocation) { - String out = ""; - try { - OutputStream outpuStream = new FileOutputStream(new File( - serverLocation)); - int read = 0; - byte[] bytes = new byte[CHUNK_SIZE_IN]; - MessageDigest md = MessageDigest.getInstance("SHA-512"); - - outpuStream = new FileOutputStream(new File(serverLocation)); - while ((read = uploadedInputStream.read(bytes)) != -1) { - //logger.debug("write {}", read); - md.update(bytes, 0, read); - outpuStream.write(bytes, 0, read); - } - logger.info("Flush input stream ... {}", serverLocation); - outpuStream.flush(); - outpuStream.close(); - // create the end of sha512 - byte[] sha512Digest = md.digest(); - // convert in hexadecimal - out = bytesToHex(sha512Digest); - uploadedInputStream.close(); - } catch (IOException ex) { - logger.error("Can not write in temporary file ... "); - ex.printStackTrace(); - } catch (NoSuchAlgorithmException ex) { - logger.error("Can not find sha512 algorithms"); - ex.printStackTrace(); - } - return out; - } - - // curl http://localhost:9993/api/users/3 - //@Secured - /* - @GET - @Path("{id}") - //@RolesAllowed("GUEST") - @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response retriveData(@HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception { - return retriveDataFull(range, id, "no-name"); - } - */ - - public static String bytesToHex(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(String.format("%02x", b)); - } - return sb.toString(); - } - + } + + public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) { + return saveFile(uploadedInputStream, getTmpFileInData(idData)); + } + + public static void removeTemporaryFile(long idData) { + String filepath = getTmpFileInData(idData); + if (Files.exists(Paths.get(filepath))) { + try { + Files.delete(Paths.get(filepath)); + } catch (IOException e) { + LOGGER.info("can not delete temporary file : {}", Paths.get(filepath)); + e.printStackTrace(); + } + } + } + + // save uploaded file to a defined location on the server + public static String saveFile(InputStream uploadedInputStream, String serverLocation) { + String out = ""; + try { + OutputStream outpuStream = new FileOutputStream(new File(serverLocation)); + int read = 0; + byte[] bytes = new byte[CHUNK_SIZE_IN]; + MessageDigest md = MessageDigest.getInstance("SHA-512"); + + outpuStream = new FileOutputStream(new File(serverLocation)); + while ((read = uploadedInputStream.read(bytes)) != -1) { + //logger.debug("write {}", read); + md.update(bytes, 0, read); + outpuStream.write(bytes, 0, read); + } + LOGGER.info("Flush input stream ... {}", serverLocation); + outpuStream.flush(); + outpuStream.close(); + // create the end of sha512 + byte[] sha512Digest = md.digest(); + // convert in hexadecimal + out = bytesToHex(sha512Digest); + uploadedInputStream.close(); + } catch (IOException ex) { + LOGGER.error("Can not write in temporary file ... "); + ex.printStackTrace(); + } catch (NoSuchAlgorithmException ex) { + LOGGER.error("Can not find sha512 algorithms"); + ex.printStackTrace(); + } + return out; + } + + // curl http://localhost:9993/api/users/3 + //@Secured + /* + @GET + @Path("{id}") + //@RolesAllowed("GUEST") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response retriveData(@HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception { + return retriveDataFull(range, id, "no-name"); + } + */ + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + public static String multipartCorrection(String data) { - if (data == null) { - return null; - } - if (data.isEmpty()) { - return null; - } - if (data.contentEquals("null")) { - return null; - } - return data; - } - - public static Response uploadCover(Class clazz, - Long id, - String fileName, - InputStream fileInputStream, - FormDataContentDisposition fileMetaData - ) { - try { - // correct input string stream : - fileName = multipartCorrection(fileName); - - //public NodeSmall uploadFile(final FormDataMultiPart form) { - logger.info("Upload media file: {}", fileMetaData); - logger.info(" - id: {}", id); - logger.info(" - file_name: ", fileName); - logger.info(" - fileInputStream: {}", fileInputStream); - logger.info(" - fileMetaData: {}", fileMetaData); - T media = SqlWrapper.get(clazz, id); - if (media == null) { - return Response.notModified("Media Id does not exist or removed...").build(); - } - - long tmpUID = getTmpDataId(); - String sha512 = saveTemporaryFile(fileInputStream, tmpUID); - Data data = getWithSha512(sha512); - if (data == null) { - logger.info("Need to add the data in the BDD ... "); - try { - data = createNewData(tmpUID, fileName, sha512); - } catch (IOException ex) { - removeTemporaryFile(tmpUID); - ex.printStackTrace(); - return Response.notModified("can not create input media").build(); - } catch (SQLException ex) { - ex.printStackTrace(); - removeTemporaryFile(tmpUID); - return Response.notModified("Error in SQL insertion ...").build(); - } - } else if (data.deleted == true) { - logger.error("Data already exist but deleted"); - undelete(data.id); - data.deleted = false; - } else { - logger.error("Data already exist ... all good"); - } - // Fist step: retrieve all the Id of each parents:... - logger.info("Find typeNode"); - SqlWrapper.addLink(clazz, id, "cover", data.id); - return Response.ok(SqlWrapper.get(clazz, id)).build(); - } catch (Exception ex) { - System.out.println("Cat ann unexpected error ... "); - ex.printStackTrace(); - } - return Response.serverError().build(); - } + if (data == null) { + return null; + } + if (data.isEmpty()) { + return null; + } + if (data.contentEquals("null")) { + return null; + } + return data; + } + + public static Response uploadCover(Class clazz, Long id, String fileName, InputStream fileInputStream, FormDataContentDisposition fileMetaData) { + try { + // correct input string stream : + fileName = multipartCorrection(fileName); + + //public NodeSmall uploadFile(final FormDataMultiPart form) { + LOGGER.info("Upload media file: {}", fileMetaData); + LOGGER.info(" - id: {}", id); + LOGGER.info(" - file_name: ", fileName); + LOGGER.info(" - fileInputStream: {}", fileInputStream); + LOGGER.info(" - fileMetaData: {}", fileMetaData); + T media = SqlWrapper.get(clazz, id); + if (media == null) { + return Response.notModified("Media Id does not exist or removed...").build(); + } + + long tmpUID = getTmpDataId(); + String sha512 = saveTemporaryFile(fileInputStream, tmpUID); + Data data = getWithSha512(sha512); + if (data == null) { + LOGGER.info("Need to add the data in the BDD ... "); + try { + data = createNewData(tmpUID, fileName, sha512); + } catch (IOException ex) { + removeTemporaryFile(tmpUID); + ex.printStackTrace(); + return Response.notModified("can not create input media").build(); + } catch (SQLException ex) { + ex.printStackTrace(); + removeTemporaryFile(tmpUID); + return Response.notModified("Error in SQL insertion ...").build(); + } + } else if (data.deleted == true) { + LOGGER.error("Data already exist but deleted"); + undelete(data.id); + data.deleted = false; + } else { + LOGGER.error("Data already exist ... all good"); + } + // Fist step: retrieve all the Id of each parents:... + LOGGER.info("Find typeNode"); + AddOnSQLTableExternalLink.addLink(clazz, id, "cover", data.id); + return Response.ok(SqlWrapper.get(clazz, id)).build(); + } catch (Exception ex) { + System.out.println("Cat ann unexpected error ... "); + ex.printStackTrace(); + } + return Response.serverError().build(); + } } diff --git a/src/org/kar/archidata/util/JWTWrapper.java b/src/org/kar/archidata/util/JWTWrapper.java index 26addbd..29c12f6 100644 --- a/src/org/kar/archidata/util/JWTWrapper.java +++ b/src/org/kar/archidata/util/JWTWrapper.java @@ -32,53 +32,54 @@ public class JWTWrapper { private static RSAKey rsaJWK = null;; private static RSAKey rsaPublicJWK = null; - + public static class PublicKey { public String key; - + public PublicKey(String key) { this.key = key; } - public PublicKey() { - } + + public PublicKey() {} } - public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException { - // check Token: - URL obj = new URL(ssoUri + "public_key"); - //logger.debug("Request token from: {}", obj); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", application); - con.setRequestProperty("Cache-Control", "no-cache"); - con.setRequestProperty("Content-Type", "application/json"); - con.setRequestProperty("Accept", "application/json"); - String ssoToken = ConfigBaseVariable.ssoToken(); - if (ssoToken != null) { - con.setRequestProperty("Authorization", "Zota " + ssoToken); - } - int responseCode = con.getResponseCode(); - - //logger.debug("GET Response Code :: {}", responseCode); - if (responseCode == HttpURLConnection.HTTP_OK) { // success - BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); - - String inputLine; - StringBuffer response = new StringBuffer(); - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - // print result - //logger.debug(response.toString()); - ObjectMapper mapper = new ObjectMapper(); - PublicKey values = mapper.readValue(response.toString(), PublicKey.class); - rsaPublicJWK = RSAKey.parse(values.key); - return; - } - logger.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj); - } - - public static void initLocalToken(String baseUUID) throws Exception{ + + public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException { + // check Token: + URL obj = new URL(ssoUri + "public_key"); + //logger.debug("Request token from: {}", obj); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", application); + con.setRequestProperty("Cache-Control", "no-cache"); + con.setRequestProperty("Content-Type", "application/json"); + con.setRequestProperty("Accept", "application/json"); + String ssoToken = ConfigBaseVariable.ssoToken(); + if (ssoToken != null) { + con.setRequestProperty("Authorization", "Zota " + ssoToken); + } + int responseCode = con.getResponseCode(); + + //logger.debug("GET Response Code :: {}", responseCode); + if (responseCode == HttpURLConnection.HTTP_OK) { // success + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + + String inputLine; + StringBuffer response = new StringBuffer(); + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + // print result + //logger.debug(response.toString()); + ObjectMapper mapper = new ObjectMapper(); + PublicKey values = mapper.readValue(response.toString(), PublicKey.class); + rsaPublicJWK = RSAKey.parse(values.key); + return; + } + logger.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj); + } + + public static void initLocalToken(String baseUUID) throws Exception { // RSA signatures require a public and private RSA key pair, the public key // must be made known to the JWS recipient in order to verify the signatures try { @@ -111,12 +112,14 @@ public class JWTWrapper { } } + public static String getPublicKeyJson() { if (rsaPublicJWK == null) { return null; } return rsaPublicJWK.toJSONString(); } + public static java.security.interfaces.RSAPublicKey getPublicKeyJava() throws JOSEException { if (rsaPublicJWK == null) { return null; @@ -146,21 +149,16 @@ public class JWTWrapper { */ try { // Create RSA-signer with the private key - JWSSigner signer = new RSASSASigner(rsaJWK); - - logger.warn("timeOutInMunites= {}", timeOutInMunites); - Date now = new Date(); - logger.warn("now = {}", now); - Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */); - - logger.warn("expiration= {}", expiration); - JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder() - .subject(Long.toString(userID)) - .claim("login", userLogin) - .claim("application", application) - .issuer(isuer) - .issueTime(now) - .expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning + JWSSigner signer = new RSASSASigner(rsaJWK); + + logger.warn("timeOutInMunites= {}", timeOutInMunites); + Date now = new Date(); + logger.warn("now = {}", now); + Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */); + + logger.warn("expiration= {}", expiration); + JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now) + .expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning // add right if needed: if (rights != null && !rights.isEmpty()) { builder.claim("right", rights); @@ -168,7 +166,7 @@ public class JWTWrapper { // Prepare JWT with claims set JWTClaimsSet claimsSet = builder.build(); SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet); - + // Compute the RSA signature signedJWT.sign(signer); // serialize the output... @@ -178,7 +176,7 @@ public class JWTWrapper { } return null; } - + public static JWTClaimsSet validateToken(String signedToken, String isuer, String application) { if (rsaPublicJWK == null) { logger.warn("JWT public key is not present !!!"); @@ -187,18 +185,18 @@ public class JWTWrapper { try { // On the consumer side, parse the JWS and verify its RSA signature SignedJWT signedJWT = SignedJWT.parse(signedToken); - + JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK); if (!signedJWT.verify(verifier)) { logger.error("JWT token is NOT verified "); return null; } if (!new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime())) { - logger.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime() ); + logger.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime()); return null; } if (!isuer.equals(signedJWT.getJWTClaimsSet().getIssuer())) { - logger.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'" ); + logger.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'"); return null; } if (application != null) { diff --git a/src/org/kar/archidata/util/PublicKey.java b/src/org/kar/archidata/util/PublicKey.java index f6968be..440d3eb 100644 --- a/src/org/kar/archidata/util/PublicKey.java +++ b/src/org/kar/archidata/util/PublicKey.java @@ -1,9 +1,8 @@ package org.kar.archidata.util; - public class PublicKey { public String key; - + public PublicKey(String key) { this.key = key; } diff --git a/src/org/kar/archidata/util/RESTApi.java b/src/org/kar/archidata/util/RESTApi.java index 93f15d8..f826fa5 100644 --- a/src/org/kar/archidata/util/RESTApi.java +++ b/src/org/kar/archidata/util/RESTApi.java @@ -31,6 +31,7 @@ public class RESTApi { public void setToken(String token) { this.token = token; } + public List gets(Class clazz, String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); @@ -44,9 +45,10 @@ public class RESTApi { RESTErrorResponseExeption out = mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); throw out; } - List out = mapper.readValue(httpResponse.body(), new TypeReference>(){}); + List out = mapper.readValue(httpResponse.body(), new TypeReference>() {}); return out; } + public T get(Class clazz, String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); @@ -59,20 +61,21 @@ public class RESTApi { if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { //LOGGER.error("catch error from REST API: {}", httpResponse.body()); RESTErrorResponseExeption out = mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class); - throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status,out.statusMessage); + throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage); } //LOGGER.error("status code: {}", httpResponse.statusCode()); //LOGGER.error("data: {}", httpResponse.body()); if (clazz.equals(String.class)) { - return (T)httpResponse.body(); + return (T) httpResponse.body(); } T out = mapper.readValue(httpResponse.body(), clazz); return out; } + public T post(Class clazz, String urlOffset, U data) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); - String body = mapper.writeValueAsString(data); + String body = mapper.writeValueAsString(data); Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset)); if (token != null) { requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token); @@ -87,15 +90,16 @@ public class RESTApi { throw out; } if (clazz.equals(String.class)) { - return (T)httpResponse.body(); + return (T) httpResponse.body(); } T out = mapper.readValue(httpResponse.body(), clazz); return out; } + public T postMap(Class clazz, String urlOffset, Map data) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); - String body = mapper.writeValueAsString(data); + String body = mapper.writeValueAsString(data); Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset)); if (token != null) { requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token); @@ -108,15 +112,16 @@ public class RESTApi { throw out; } if (clazz.equals(String.class)) { - return (T)httpResponse.body(); + return (T) httpResponse.body(); } T out = mapper.readValue(httpResponse.body(), clazz); return out; } + public T put(Class clazz, String urlOffset, U data) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); - String body = mapper.writeValueAsString(data); + String body = mapper.writeValueAsString(data); Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset)); if (token != null) { requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token); @@ -129,15 +134,16 @@ public class RESTApi { throw out; } if (clazz.equals(String.class)) { - return (T)httpResponse.body(); + return (T) httpResponse.body(); } T out = mapper.readValue(httpResponse.body(), clazz); return out; } + public T putMap(Class clazz, String urlOffset, Map data) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); - String body = mapper.writeValueAsString(data); + String body = mapper.writeValueAsString(data); Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset)); if (token != null) { requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token); @@ -150,11 +156,12 @@ public class RESTApi { throw out; } if (clazz.equals(String.class)) { - return (T)httpResponse.body(); + return (T) httpResponse.body(); } T out = mapper.readValue(httpResponse.body(), clazz); return out; } + public T delete(Class clazz, String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException { ObjectMapper mapper = new ObjectMapper(); HttpClient client = HttpClient.newHttpClient(); @@ -169,7 +176,7 @@ public class RESTApi { throw out; } if (clazz.equals(String.class)) { - return (T)httpResponse.body(); + return (T) httpResponse.body(); } T out = mapper.readValue(httpResponse.body(), clazz); return out; diff --git a/test/src/test/kar/archidata/TestBase.java b/test/src/test/kar/archidata/TestBase.java new file mode 100644 index 0000000..0e03170 --- /dev/null +++ b/test/src/test/kar/archidata/TestBase.java @@ -0,0 +1,44 @@ +package test.kar.archidata; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.kar.archidata.sqlWrapper.SqlWrapper; +import org.kar.archidata.util.RESTApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestBase { + final static Logger logger = LoggerFactory.getLogger(TestBase.class); + + static RESTApi api = null; + + @BeforeAll + public static void configureWebServer() throws Exception { + logger.info("Create DB"); + final String dbName = "sdfsdfsdfsfsdfsfsfsfsdfsdfsd"; + boolean data = SqlWrapper.isDBExist(dbName); + logger.error("exist: {}", data); + data = SqlWrapper.createDB(dbName); + logger.error("create: {}", data); + data = SqlWrapper.isDBExist(dbName); + logger.error("exist: {}", data); + } + + @AfterAll + public static void stopWebServer() throws InterruptedException { + logger.info("Kill the web server"); + // TODO: do it better... + } + + @Order(1) + @Test + public void checkSimpleTestError() throws Exception { + Assertions.assertEquals("lkjlkjlkjlk", "alive and kicking"); + } +}