diff --git a/.classpath b/.classpath index 827acf2..6c8fcb3 100644 --- a/.classpath +++ b/.classpath @@ -23,5 +23,22 @@ + + + + + + + + + + + + + + + + + diff --git a/src/org/kar/archidata/UserDB.java b/src/org/kar/archidata/UserDB.java index 1e9fb44..a082861 100755 --- a/src/org/kar/archidata/UserDB.java +++ b/src/org/kar/archidata/UserDB.java @@ -2,6 +2,7 @@ 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; diff --git a/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java b/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java index b8f9632..e2cbcc6 100644 --- a/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java +++ b/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java @@ -11,10 +11,22 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLTableLinkGeneric { + public static String AUTOMATIC ="__auto__"; public enum ModelLink { NONE, - INTERNAL, - EXTERNAL + 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 + 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/api/DataResource.java b/src/org/kar/archidata/api/DataResource.java index 6bb7a46..8a696c9 100644 --- a/src/org/kar/archidata/api/DataResource.java +++ b/src/org/kar/archidata/api/DataResource.java @@ -4,7 +4,7 @@ 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; +import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.archidata.annotation.security.PermitTokenInURI; import org.kar.archidata.annotation.security.RolesAllowed; import org.kar.archidata.util.ConfigBaseVariable; diff --git a/src/org/kar/archidata/db/DBConfig.java b/src/org/kar/archidata/db/DBConfig.java index 8fbd47b..6733ea5 100644 --- a/src/org/kar/archidata/db/DBConfig.java +++ b/src/org/kar/archidata/db/DBConfig.java @@ -1,6 +1,6 @@ package org.kar.archidata.db; -import org.kar.archidata.SqlWrapper; +import org.kar.archidata.sqlWrapper.SqlWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/org/kar/archidata/migration/MigrationEngine.java b/src/org/kar/archidata/migration/MigrationEngine.java index ff32eb9..62736b6 100644 --- a/src/org/kar/archidata/migration/MigrationEngine.java +++ b/src/org/kar/archidata/migration/MigrationEngine.java @@ -5,9 +5,9 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import org.kar.archidata.SqlWrapper; import org.kar.archidata.db.DBConfig; import org.kar.archidata.db.DBEntry; +import org.kar.archidata.sqlWrapper.SqlWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/org/kar/archidata/migration/MigrationSqlStep.java b/src/org/kar/archidata/migration/MigrationSqlStep.java index 94f24b5..d3b956f 100644 --- a/src/org/kar/archidata/migration/MigrationSqlStep.java +++ b/src/org/kar/archidata/migration/MigrationSqlStep.java @@ -5,8 +5,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import org.kar.archidata.SqlWrapper; import org.kar.archidata.db.DBEntry; +import org.kar.archidata.sqlWrapper.SqlWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/org/kar/archidata/SqlWrapper.java b/src/org/kar/archidata/sqlWrapper/SqlWrapper.java similarity index 95% rename from src/org/kar/archidata/SqlWrapper.java rename to src/org/kar/archidata/sqlWrapper/SqlWrapper.java index 9bb672e..f2d5da7 100644 --- a/src/org/kar/archidata/SqlWrapper.java +++ b/src/org/kar/archidata/sqlWrapper/SqlWrapper.java @@ -1,4 +1,4 @@ -package org.kar.archidata; +package org.kar.archidata.sqlWrapper; import java.io.IOException; import java.lang.annotation.Annotation; @@ -11,6 +11,7 @@ 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.SQLIfNotExists; @@ -38,6 +39,11 @@ 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) { + SqlWrapper.addOn.add(addOn); + }; public static class ExceptionDBInterface extends Exception { private static final long serialVersionUID = 1L; @@ -395,6 +401,10 @@ public class SqlWrapper { 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) { continue; @@ -445,6 +455,10 @@ public class SqlWrapper { Field primaryKeyField = null; 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) { primaryKeyField = elem; @@ -567,6 +581,10 @@ public class SqlWrapper { 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) { primaryKeyField = elem; @@ -615,6 +633,10 @@ public class SqlWrapper { 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) { continue; @@ -822,6 +844,10 @@ public class SqlWrapper { 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) { continue; @@ -879,6 +905,10 @@ public class SqlWrapper { 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; @@ -913,6 +943,10 @@ public class SqlWrapper { 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) { primaryKeyField = elem; @@ -948,13 +982,20 @@ public class SqlWrapper { 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; if (!full && notRead) { autoClasify[indexAutoClasify++] = StateLoad.DISABLE; continue; } + if (!hasDeleted) { + hasDeleted = elem.getDeclaredAnnotationsByType(SQLDeleted.class).length != 0; + } String name = elem.getName(); count++; if (firstField) { @@ -962,6 +1003,8 @@ public class SqlWrapper { } else { query.append(","); } + + ModelLink linkGeneric = getLinkMode(elem); if (linkGeneric == ModelLink.EXTERNAL) { autoClasify[indexAutoClasify++] = StateLoad.ARRAY; @@ -1017,14 +1060,16 @@ public class SqlWrapper { query.append(" FROM `"); query.append(tableName); query.append("` "); - query.append(" WHERE "); - //query.append(tableName); - //query.append("."); - //query.append(primaryKeyField.getName()); - //query.append(" = ?"); - //query.append(" AND "); - query.append(tableName); - query.append(".deleted = false "); + 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()); @@ -1041,6 +1086,9 @@ public class SqlWrapper { 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; */ @@ -1255,6 +1303,10 @@ public class SqlWrapper { 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; + } String name = elem.getName(); Integer limitSize = getLimitSize(elem); @@ -1373,8 +1425,8 @@ public class SqlWrapper { out.append(" "); } if (updateTime) { - out.append("ON UPDATE CURRENT_TIMESTAMP"); if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + out.append("ON UPDATE CURRENT_TIMESTAMP"); out.append("(3)"); } out.append(" "); @@ -1388,8 +1440,8 @@ public class SqlWrapper { } out.append(" "); if (updateTime) { - out.append("ON UPDATE CURRENT_TIMESTAMP"); if (!ConfigBaseVariable.getDBType().equals("sqlite")) { + out.append("ON UPDATE CURRENT_TIMESTAMP"); out.append("(3)"); } out.append(" "); diff --git a/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java b/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java new file mode 100644 index 0000000..35ad376 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/SqlWrapperAddOn.java @@ -0,0 +1,24 @@ +package org.kar.archidata.sqlWrapper; + +import java.lang.reflect.Field; + +public interface SqlWrapperAddOn { + /** + * Get the Class of the declaration annotation + * @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. + * @return True of the field is manage by the current Add-on. + */ + boolean isCompatibleField(Field elem); + +} diff --git a/src/org/kar/archidata/WhereCondition.java b/src/org/kar/archidata/sqlWrapper/WhereCondition.java similarity index 69% rename from src/org/kar/archidata/WhereCondition.java rename to src/org/kar/archidata/sqlWrapper/WhereCondition.java index 5c325d7..86f7f5b 100644 --- a/src/org/kar/archidata/WhereCondition.java +++ b/src/org/kar/archidata/sqlWrapper/WhereCondition.java @@ -1,4 +1,4 @@ -package org.kar.archidata; +package org.kar.archidata.sqlWrapper; public record WhereCondition( String key, diff --git a/src/org/kar/archidata/sqlWrapper/addOn/ExternalLink.java b/src/org/kar/archidata/sqlWrapper/addOn/ExternalLink.java new file mode 100644 index 0000000..c040a91 --- /dev/null +++ b/src/org/kar/archidata/sqlWrapper/addOn/ExternalLink.java @@ -0,0 +1,21 @@ +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/DataTools.java b/src/org/kar/archidata/util/DataTools.java index 9aa48b9..5954e4d 100644 --- a/src/org/kar/archidata/util/DataTools.java +++ b/src/org/kar/archidata/util/DataTools.java @@ -15,8 +15,8 @@ import java.sql.SQLException; import jakarta.ws.rs.core.Response; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; -import org.kar.archidata.SqlWrapper; import org.kar.archidata.model.Data; +import org.kar.archidata.sqlWrapper.SqlWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory;