Compare commits

...

24 Commits

Author SHA1 Message Date
713f84e2da [RELEASE] Release v0.20.0 2025-01-05 21:56:35 +01:00
d3a7db4f21 [FEAT] update ObjectId for data 2025-01-05 21:41:19 +01:00
ea8e2cc452 [FIX] system.out removing to use all time LOGGER 2025-01-05 21:40:39 +01:00
ee831283d3 [FIX] dynamc modification type for DataJson 2025-01-02 23:06:27 +01:00
6b12d26a8b [FIX] remove comment 2025-01-02 23:05:47 +01:00
59e40a40d4 [FIX] simple correction of typing 2025-01-02 23:05:08 +01:00
b6bf7acd79 [FEAT] use a generic ObjectMapper factory to support the same suset of the tools 2025-01-02 23:04:10 +01:00
b581702df4 [FIX] corrent the search of primary key to support Morphia 2025-01-02 23:01:13 +01:00
645c8b1364 [FEAT] add capability to change the name of the field (not full tested but base is working) 2025-01-02 18:01:02 +01:00
54d3f52bd3 [FEAT] support ManyToMany agnostic primary keys 2025-01-01 18:21:41 +01:00
71f69fb7cf [FEAT] Simplify interface of the ManyToMany (internal) add capability to overwrite the type of an object 2025-01-01 18:06:50 +01:00
f5d25380c7 [FEAT] add basic element to support ObjectId as native primary Key (not tested) 2025-01-01 11:18:47 +01:00
61dde0f0ed [FEAT] add capability to check the JPA fields to prevent refacto erors 2024-12-31 16:14:35 +01:00
e3dd58910e [FEAT] add DataJson(checker ...) availlable in JPA 2024-12-31 15:59:14 +01:00
841514935c [FIX] missing model test class 2024-12-31 10:41:14 +01:00
5f682da13e [FIX] variable access 2024-12-31 10:40:50 +01:00
01560cd285 [FEAT] support native ISO8601 Time serialisation in the tool rest APi and the data
need to call the ContextGenericTools.addJsr310(rc); to register it
2024-12-29 18:21:31 +01:00
b6464b7962 [FEAT] update all the interface to support MONGO DB 2024-12-29 17:12:28 +01:00
83977e060c [FEAT] remove some deprecated throws 2024-12-29 17:11:20 +01:00
359f235274 [FEAT] add dependency with morphia (mongo db interface wrapper) 2024-12-29 17:11:00 +01:00
b0d565b014 [FEAT] remove static from DataAPI 2024-12-29 16:22:20 +01:00
fe84af5d96 [FEAT] add some annoatation tools 2024-12-29 16:22:03 +01:00
add346cf29 [FEAT] add get userID 2024-12-23 23:56:12 +01:00
8d63a758f7 [VERSION] update dev tag version 2024-12-12 09:16:21 +01:00
141 changed files with 8220 additions and 3888 deletions

31
pom.xml
View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId> <groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.19.0</version> <version>0.20.0</version>
<properties> <properties>
<java.version>21</java.version> <java.version>21</java.version>
<maven.compiler.version>3.1</maven.compiler.version> <maven.compiler.version>3.1</maven.compiler.version>
@ -134,18 +134,18 @@
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>2.18.0-rc1</version> <version>2.18.1</version>
</dependency> </dependency>
<!-- encode output in CSV --> <!-- encode output in CSV -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId> <groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId> <artifactId>jackson-dataformat-csv</artifactId>
<version>2.18.0-rc1</version> <version>2.18.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId> <artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.0-rc1</version> <version>2.18.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
@ -188,6 +188,29 @@
<version>4.8.6</version> <version>4.8.6</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<!-- Morphia -->
<dependency>
<groupId>dev.morphia.morphia</groupId>
<artifactId>morphia-core</artifactId>
<version>2.3.0</version>
</dependency>
<!-- MongoDB Java Driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.3.0</version>
</dependency>
<!-- Bean Validation (JSR 303 / 380) -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.0.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- <!--
************************************************************ ************************************************************
** TEST dependency ** ** TEST dependency **

View File

@ -99,7 +99,7 @@ public class WebLauncher {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
System.out.println("Stopping server.."); WebLauncher.LOGGER.info("Stopping server..");
serverLink.shutdownNow(); serverLink.shutdownNow();
} }
}, "shutdownHook")); }, "shutdownHook"));

View File

@ -1,15 +0,0 @@
package org.kar.archidata;
import org.kar.archidata.db.DBConfig;
import org.kar.archidata.tools.ConfigBaseVariable;
public class GlobalConfiguration {
public static final DBConfig dbConfig;
static {
dbConfig = new DBConfig(ConfigBaseVariable.getDBType(), ConfigBaseVariable.getDBHost(),
Integer.parseInt(ConfigBaseVariable.getDBPort()), ConfigBaseVariable.getDBLogin(),
ConfigBaseVariable.getDBPassword(), ConfigBaseVariable.getDBName(),
ConfigBaseVariable.getDBKeepConnected());
}
}

View File

@ -2,14 +2,17 @@ package org.kar.archidata;
import org.kar.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper; import org.kar.archidata.tools.JWTWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UpdateJwtPublicKey extends Thread { public class UpdateJwtPublicKey extends Thread {
private static final Logger LOGGER = LoggerFactory.getLogger(UpdateJwtPublicKey.class);
boolean kill = false; boolean kill = false;
@Override @Override
public void run() { public void run() {
if (ConfigBaseVariable.getSSOAddress() == null) { if (ConfigBaseVariable.getSSOAddress() == null) {
System.out.println("SSO INTERFACE is not provided ==> work alone."); LOGGER.warn("SSO INTERFACE is not provided ==> work alone.");
// No SO provided, kill the thread. // No SO provided, kill the thread.
return; return;
} }
@ -19,7 +22,7 @@ public class UpdateJwtPublicKey extends Thread {
JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata"); JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata");
} catch (final Exception e1) { } catch (final Exception e1) {
e1.printStackTrace(); e1.printStackTrace();
System.out.println("Can not retreive the basic tocken"); LOGGER.error("Can not retreive the basic tocken");
return; return;
} }
try { try {

View File

@ -1,48 +0,0 @@
package org.kar.archidata;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.DBInterfaceOption;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.model.User;
public class UserDB {
public UserDB() {}
public static User getUsers(final long userId, QueryOption... option) throws Exception {
return DataAccess.get(User.class, userId, option);
}
public static User getUserOrCreate(final long userId, final String userLogin, QueryOption... option)
throws Exception {
final User user = getUsers(userId);
if (user != null) {
return user;
}
createUsersInfoFromOAuth(userId, userLogin, option);
return getUsers(userId);
}
private static void createUsersInfoFromOAuth(final long userId, final String login, QueryOption... option)
throws IOException {
QueryOptions options = new QueryOptions(option);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')";
try {
final PreparedStatement ps = entry.connection.prepareStatement(query);
ps.setLong(1, userId);
ps.setString(2, login);
ps.executeUpdate();
} catch (final SQLException throwables) {
throwables.printStackTrace();
} finally {
entry.close();
}
}
}

View File

@ -6,11 +6,14 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.kar.archidata.dataAccess.options.OverrideTableName; import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import dev.morphia.annotations.Entity;
import dev.morphia.mapping.Mapper;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
@ -32,6 +35,7 @@ import jakarta.ws.rs.DefaultValue;
public class AnnotationTools { public class AnnotationTools {
static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class); static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class);
// For SQL declaration table Name
public static String getTableName(final Class<?> clazz, final QueryOptions options) throws DataAccessException { public static String getTableName(final Class<?> clazz, final QueryOptions options) throws DataAccessException {
if (options != null) { if (options != null) {
final List<OverrideTableName> data = options.get(OverrideTableName.class); final List<OverrideTableName> data = options.get(OverrideTableName.class);
@ -42,16 +46,13 @@ public class AnnotationTools {
return AnnotationTools.getTableName(clazz); return AnnotationTools.getTableName(clazz);
} }
public static String getTableName(final Class<?> element) throws DataAccessException { // For SQL declaration table Name
public static String getTableName(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class);
if (annotation.length == 0) { if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name // when no annotation is detected, then the table name is the class name
return element.getSimpleName(); return element.getSimpleName();
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Table on " + element.getClass().getCanonicalName());
}
final String tmp = ((Table) annotation[0]).name(); final String tmp = ((Table) annotation[0]).name();
if (tmp == null) { if (tmp == null) {
return element.getSimpleName(); return element.getSimpleName();
@ -59,27 +60,44 @@ public class AnnotationTools {
return tmp; return tmp;
} }
public static boolean getSchemaReadOnly(final Field element) throws DataAccessException { public static String getCollectionName(final Class<?> clazz, final QueryOptions options) {
if (options != null) {
// TODO: maybe change OverrideTableName with OverrideCollectionName
final List<OverrideTableName> data = options.get(OverrideTableName.class);
if (data.size() == 1) {
return data.get(0).getName();
}
}
return AnnotationTools.getCollectionName(clazz);
}
// For No-SQL Table/Collection Name
public static String getCollectionName(final Class<?> clazz) {
final Annotation[] annotation = clazz.getDeclaredAnnotationsByType(Entity.class);
if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name
return clazz.getSimpleName();
}
final String tmp = ((Entity) annotation[0]).value();
if (tmp == null || tmp.length() == 0 || Mapper.IGNORED_FIELDNAME.equals(tmp)) {
return clazz.getSimpleName();
}
return tmp;
}
public static boolean getSchemaReadOnly(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return false; return false;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).readOnly(); return ((Schema) annotation[0]).readOnly();
} }
public static String getSchemaExample(final Class<?> element) throws DataAccessException { public static String getSchemaExample(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).example(); return ((Schema) annotation[0]).example();
} }
@ -91,51 +109,27 @@ public class AnnotationTools {
return true; return true;
} }
public static String getSchemaDescription(final Class<?> element) throws DataAccessException { public static String getSchemaDescription(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).description(); return ((Schema) annotation[0]).description();
} }
public static String getSchemaDescription(final Field element) throws DataAccessException { public static String getSchemaDescription(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Schema on " + element.getClass().getCanonicalName());
}
return ((Schema) annotation[0]).description(); return ((Schema) annotation[0]).description();
} }
public static String getComment(final Field element) throws DataAccessException { public static String getDefault(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataComment.class);
if (annotation.length == 0) {
return getSchemaDescription(element);
}
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @DataComment on " + element.getClass().getCanonicalName());
}
return ((DataComment) annotation[0]).value();
}
public static String getDefault(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DefaultValue.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(DefaultValue.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @DataDefault on " + element.getClass().getCanonicalName());
}
return ((DefaultValue) annotation[0]).value(); return ((DefaultValue) annotation[0]).value();
} }
@ -163,80 +157,56 @@ public class AnnotationTools {
return (OneToMany) annotation[0]; return (OneToMany) annotation[0];
} }
public static DataJson getDataJson(final Field element) throws DataAccessException { public static DataJson getDataJson(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataJson.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataJson.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @ManyToOne on " + element.getClass().getCanonicalName());
}
return (DataJson) annotation[0]; return (DataJson) annotation[0];
} }
public static Long getConstraintsMax(final Field element) throws DataAccessException { public static Long getConstraintsMax(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Max.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Max.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Size on " + element.getClass().getCanonicalName());
}
return ((Max) annotation[0]).value(); return ((Max) annotation[0]).value();
} }
public static Long getConstraintsMin(final Field element) throws DataAccessException { public static Long getConstraintsMin(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Min.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Min.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Size on " + element.getClass().getCanonicalName());
}
return ((Min) annotation[0]).value(); return ((Min) annotation[0]).value();
} }
public static int getLimitSize(final Field element) throws DataAccessException { public static int getLimitSize(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return 255; return 255;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
final int length = ((Column) annotation[0]).length(); final int length = ((Column) annotation[0]).length();
return length <= 0 ? 0 : length; return length <= 0 ? 0 : length;
} }
public static Size getConstraintsSize(final Field element) throws DataAccessException { public static Size getConstraintsSize(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Size.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Size.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Size on " + element.getClass().getCanonicalName());
}
return (Size) annotation[0]; return (Size) annotation[0];
} }
public static String getConstraintsPattern(final Field element) throws DataAccessException { public static String getConstraintsPattern(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Pattern.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Pattern.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Pattern on " + element.getClass().getCanonicalName());
}
return ((Pattern) annotation[0]).regexp(); return ((Pattern) annotation[0]).regexp();
} }
public static boolean getConstraintsEmail(final Field element) throws DataAccessException { public static boolean getConstraintsEmail(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Email.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Email.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return false; return false;
@ -267,7 +237,7 @@ public class AnnotationTools {
return false; return false;
} }
public static String getFieldName(final Field element) { public static String getFieldNameRaw(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return element.getName(); return element.getName();
@ -279,19 +249,35 @@ public class AnnotationTools {
return name; return name;
} }
public static boolean getColumnNotNull(final Field element) throws DataAccessException { public record FieldName(
String inStruct,
String inTable) {};
public static FieldName getFieldName(final Field element, final QueryOptions options) {
final String inStructName = getFieldNameRaw(element);
String inTableName = inStructName;
if (options != null) {
final List<OptionRenameColumn> renamesColumn = options.get(OptionRenameColumn.class);
for (final OptionRenameColumn rename : renamesColumn) {
if (rename.columnName.equals(inStructName)) {
inTableName = rename.colomnNewName;
LOGGER.trace("Detect overwrite of column name '{}' => '{}'", inStructName, inTableName);
break;
}
}
}
return new FieldName(inStructName, inTableName);
}
public static boolean getColumnNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return false; return false;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
return !((Column) annotation[0]).nullable(); return !((Column) annotation[0]).nullable();
} }
public static boolean getNullable(final Field element) throws DataAccessException { public static boolean getNullable(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Nullable.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Nullable.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return false; return false;
@ -299,19 +285,15 @@ public class AnnotationTools {
return true; return true;
} }
public static boolean getConstraintsNotNull(final Field element) throws DataAccessException { public static boolean getConstraintsNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NotNull.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(NotNull.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return false; return false;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @NotNull on " + element.getClass().getCanonicalName());
}
return true; return true;
} }
public static Field getPrimaryKeyField(final Class<?> clazz) throws DataAccessException { public static Field getPrimaryKeyField(final Class<?> clazz) {
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@ -324,59 +306,59 @@ public class AnnotationTools {
return null; return null;
} }
public static boolean isPrimaryKey(final Field element) throws DataAccessException { public static boolean isPrimaryKey(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Id.class); final Annotation[] annotationSQL = element.getDeclaredAnnotationsByType(Id.class);
if (annotation.length == 0) { if (annotationSQL.length > 0) {
return false; return true;
} }
return true; final Annotation[] annotationMongo = element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class);
if (annotationMongo.length > 0) {
return true;
}
return false;
} }
public static boolean isUnique(final Field element) throws DataAccessException { public static boolean isUnique(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return false; return false;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
return ((Column) annotation[0]).unique(); return ((Column) annotation[0]).unique();
} }
public static GenerationType getStrategy(final Field element) throws DataAccessException { public static GenerationType getStrategy(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return null; return null;
} }
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
return ((GeneratedValue) annotation[0]).strategy(); return ((GeneratedValue) annotation[0]).strategy();
} }
public static boolean isDeletedField(final Field element) throws DataAccessException { public static boolean isDeletedField(final Field element) {
return element.getDeclaredAnnotationsByType(DataDeleted.class).length != 0; return element.getDeclaredAnnotationsByType(DataDeleted.class).length != 0;
} }
public static boolean isCreatedAtField(final Field element) throws DataAccessException { public static boolean isCreatedAtField(final Field element) {
return element.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; return element.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
} }
public static boolean isUpdateAtField(final Field element) throws DataAccessException { public static boolean isUpdateAtField(final Field element) {
return element.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; return element.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
} }
public static boolean isdefaultNotRead(final Field element) throws DataAccessException { public static boolean isDefaultNotRead(final Field element) {
return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0; return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0;
} }
public static boolean isIdField(final Field element) throws DataAccessException { public static boolean isIdField(final Field element) {
return element.getDeclaredAnnotationsByType(Id.class).length != 0; if (element.getDeclaredAnnotationsByType(Id.class).length != 0) {
return true;
}
return element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class).length != 0;
} }
public static String getDeletedFieldName(final Class<?> clazz) throws DataAccessException { // Note: delete field can not be renamed with OptionRenameColumn
public static String getDeletedFieldName(final Class<?> clazz) {
try { try {
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
@ -384,7 +366,7 @@ public class AnnotationTools {
continue; continue;
} }
if (AnnotationTools.isDeletedField(elem)) { if (AnnotationTools.isDeletedField(elem)) {
return AnnotationTools.getFieldName(elem); return AnnotationTools.getFieldNameRaw(elem);
} }
} }
} catch (final Exception ex) { } catch (final Exception ex) {
@ -393,7 +375,8 @@ public class AnnotationTools {
return null; return null;
} }
public static String getUpdatedFieldName(final Class<?> clazz) throws DataAccessException { // Note: update field can not be renamed with OptionRenameColumn
public static String getUpdatedFieldName(final Class<?> clazz) {
try { try {
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
@ -401,7 +384,7 @@ public class AnnotationTools {
continue; continue;
} }
if (AnnotationTools.isUpdateAtField(elem)) { if (AnnotationTools.isUpdateAtField(elem)) {
return AnnotationTools.getFieldName(elem); return AnnotationTools.getFieldNameRaw(elem);
} }
} }
} catch (final Exception ex) { } catch (final Exception ex) {
@ -427,16 +410,28 @@ public class AnnotationTools {
return null; return null;
} }
public static List<String> getFieldsNames(final Class<?> clazz) throws DataAccessException { public static boolean hasFieldsName(final Class<?> clazz, final String name) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.getFieldNameRaw(field).equals(name)) {
return true;
}
}
return false;
}
public static List<String> getFieldsNames(final Class<?> clazz) {
return getFieldsNamesFilter(clazz, false); return getFieldsNamesFilter(clazz, false);
} }
public static List<String> getAllFieldsNames(final Class<?> clazz) throws DataAccessException { public static List<String> getAllFieldsNames(final Class<?> clazz) {
return getFieldsNamesFilter(clazz, true); return getFieldsNamesFilter(clazz, true);
} }
private static List<String> getFieldsNamesFilter(final Class<?> clazz, final boolean full) private static List<String> getFieldsNamesFilter(final Class<?> clazz, final boolean full) {
throws DataAccessException {
final List<String> out = new ArrayList<>(); final List<String> out = new ArrayList<>();
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
@ -446,17 +441,17 @@ public class AnnotationTools {
if (!full && AnnotationTools.isGenericField(field)) { if (!full && AnnotationTools.isGenericField(field)) {
continue; continue;
} }
out.add(AnnotationTools.getFieldName(field)); out.add(AnnotationTools.getFieldNameRaw(field));
} }
return out; return out;
} }
public static boolean isGenericField(final Field elem) throws DataAccessException { public static boolean isGenericField(final Field elem) {
return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem) return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem)
|| AnnotationTools.isUpdateAtField(elem) || AnnotationTools.isDeletedField(elem); || AnnotationTools.isUpdateAtField(elem) || AnnotationTools.isDeletedField(elem);
} }
public static Field getFieldOfId(final Class<?> clazz) throws DataAccessException { public static Field getFieldOfId(final Class<?> clazz) {
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@ -469,13 +464,13 @@ public class AnnotationTools {
return null; return null;
} }
public static Field getFieldNamed(final Class<?> clazz, final String name) throws DataAccessException { public static Field getFieldNamed(final Class<?> clazz, final String name) {
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it .. // static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue; continue;
} }
if (AnnotationTools.getFieldName(field).equals(name)) { if (AnnotationTools.getFieldNameRaw(field).equals(name)) {
return field; return field;
} }
} }

View File

@ -1,13 +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, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Deprecated(since = "0.5.2")
public @interface DataComment {
String value();
}

View File

@ -21,6 +21,7 @@ import java.util.UUID;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.security.PermitTokenInURI; import org.kar.archidata.annotation.security.PermitTokenInURI;
@ -86,24 +87,25 @@ public class DataResource {
return filePath; return filePath;
} }
public static String getFileDataOld(final long tmpFolderId) { public static String getFileDataOld(final UUID uuid) {
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator final String stringUUID = uuid.toString();
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + stringUUID + File.separator
+ "data"; + "data";
try { try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + stringUUID + File.separator);
} catch (final IOException e) { } catch (final IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
return filePath; return filePath;
} }
public static String getFileData(final UUID uuid) { public static String getFileData(final ObjectId oid) {
final String stringUUID = uuid.toString(); final String stringOid = oid.toHexString();
final String part1 = stringUUID.substring(0, 2); final String part1 = stringOid.substring(0, 2);
final String part2 = stringUUID.substring(2, 4); final String part2 = stringOid.substring(2, 4);
final String part3 = stringUUID.substring(4); final String part3 = stringOid.substring(4);
final String finalPath = part1 + File.separator + part2; final String finalPath = part1 + File.separator + part2;
String filePath = ConfigBaseVariable.getMediaDataFolder() + "_uuid" + File.separator + finalPath String filePath = ConfigBaseVariable.getMediaDataFolder() + "_oid" + File.separator + finalPath
+ File.separator; + File.separator;
try { try {
createFolder(filePath); createFolder(filePath);
@ -114,11 +116,11 @@ public class DataResource {
return filePath; return filePath;
} }
public static String getFileMetaData(final UUID uuid) { public static String getFileMetaData(final ObjectId oid) {
return getFileData(uuid) + ".json"; return getFileData(oid) + ".json";
} }
public static Data getWithSha512(final String sha512) { public Data getWithSha512(final String sha512) {
LOGGER.info("find sha512 = {}", sha512); LOGGER.info("find sha512 = {}", sha512);
try { try {
return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512))); return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)));
@ -129,7 +131,7 @@ public class DataResource {
return null; return null;
} }
public static Data getWithId(final long id) { public Data getWithId(final long id) {
LOGGER.info("find id = {}", id); LOGGER.info("find id = {}", id);
try { try {
return DataAccess.get(Data.class, id); return DataAccess.get(Data.class, id);
@ -140,7 +142,7 @@ public class DataResource {
return null; return null;
} }
public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512) public Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
throws IOException { throws IOException {
// determine mime type: // determine mime type:
Data injectedData = new Data(); Data injectedData = new Data();
@ -166,7 +168,7 @@ public class DataResource {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
final String mediaPath = getFileData(injectedData.uuid); final String mediaPath = getFileData(injectedData.oid);
LOGGER.info("src = {}", tmpPath); LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath); LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
@ -174,9 +176,9 @@ public class DataResource {
return injectedData; return injectedData;
} }
public static void modeFileOldModelToNewModel(final long id, final UUID uuid) throws IOException { public static void modeFileOldModelToNewModel(final UUID uuid, final ObjectId oid) throws IOException {
String mediaCurentPath = getFileDataOld(id); String mediaCurentPath = getFileDataOld(uuid);
String mediaDestPath = getFileData(uuid); String mediaDestPath = getFileData(oid);
LOGGER.info("src = {}", mediaCurentPath); LOGGER.info("src = {}", mediaCurentPath);
LOGGER.info("dst = {}", mediaDestPath); LOGGER.info("dst = {}", mediaDestPath);
if (Files.exists(Paths.get(mediaCurentPath))) { if (Files.exists(Paths.get(mediaCurentPath))) {
@ -252,9 +254,9 @@ public class DataResource {
return sb.toString(); return sb.toString();
} }
public Data getSmall(final UUID id) { public Data getSmall(final ObjectId oid) {
try { try {
return DataAccess.get(Data.class, id); return DataAccess.get(Data.class, oid);
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -288,7 +290,7 @@ public class DataResource {
} }
@GET @GET
@Path("{uuid}") @Path("{oid}")
@PermitTokenInURI @PermitTokenInURI
@RolesAllowed("USER") @RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_OCTET_STREAM)
@ -297,19 +299,17 @@ public class DataResource {
@Context final SecurityContext sc, @Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token, @QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range, @HeaderParam("Range") final String range,
@PathParam("uuid") final UUID uuid) throws FailException { @PathParam("oid") final ObjectId oid) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal(); final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("==================================================="); // logger.info("===================================================");
LOGGER.info("== DATA retrieveDataId ? id={} user={}", uuid, (gc == null ? "null" : gc.userByToken)); LOGGER.info("== DATA retrieveDataId ? oid={} user={}", oid, (gc == null ? "null" : gc.userByToken));
// logger.info("==================================================="); // logger.info("===================================================");
final Data value = getSmall(uuid); final Data value = getSmall(oid);
if (value == null) { if (value == null) {
LOGGER.warn("Request data that does not exist : {}", uuid); return Response.status(404).entity("media NOT FOUND: " + oid).type("text/plain").build();
return Response.status(404).entity("media NOT FOUND: " + uuid).type("text/plain").build();
} }
try { try {
LOGGER.warn("Generate stream : {}", uuid); return buildStream(getFileData(oid), range,
return buildStream(getFileData(uuid), range,
value.mimeType == null ? "application/octet-stream" : value.mimeType); value.mimeType == null ? "application/octet-stream" : value.mimeType);
} catch (final Exception ex) { } catch (final Exception ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to build output stream", ex); throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to build output stream", ex);
@ -317,7 +317,7 @@ public class DataResource {
} }
@GET @GET
@Path("thumbnail/{uuid}") @Path("thumbnail/{oid}")
@RolesAllowed("USER") @RolesAllowed("USER")
@PermitTokenInURI @PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_OCTET_STREAM)
@ -327,19 +327,19 @@ public class DataResource {
@Context final SecurityContext sc, @Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token, @QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range, @HeaderParam("Range") final String range,
@PathParam("uuid") final UUID uuid) throws FailException { @PathParam("oid") final ObjectId oid) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal(); final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("==================================================="); LOGGER.info("===================================================");
LOGGER.info("== DATA retrieveDataThumbnailId ? {}", (gc == null ? "null" : gc.userByToken)); LOGGER.info("== DATA retrieveDataThumbnailId ? {}", (gc == null ? "null" : gc.userByToken));
LOGGER.info("==================================================="); LOGGER.info("===================================================");
final Data value = getSmall(uuid); final Data value = getSmall(oid);
if (value == null) { if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + uuid).type("text/plain").build(); return Response.status(404).entity("media NOT FOUND: " + oid).type("text/plain").build();
} }
final String filePathName = getFileData(uuid); final String filePathName = getFileData(oid);
final File inputFile = new File(filePathName); final File inputFile = new File(filePathName);
if (!inputFile.exists()) { if (!inputFile.exists()) {
return Response.status(404).entity("{\"error\":\"media Does not exist: " + uuid + "\"}") return Response.status(404).entity("{\"error\":\"media Does not exist: " + oid + "\"}")
.type("application/json").build(); .type("application/json").build();
} }
if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png") if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png")
@ -404,7 +404,7 @@ public class DataResource {
} }
@GET @GET
@Path("{uuid}/{name}") @Path("{oid}/{name}")
@PermitTokenInURI @PermitTokenInURI
@RolesAllowed("USER") @RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_OCTET_STREAM)
@ -413,17 +413,17 @@ public class DataResource {
@Context final SecurityContext sc, @Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token, @QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range, @HeaderParam("Range") final String range,
@PathParam("uuid") final UUID uuid, @PathParam("oid") final ObjectId oid,
@PathParam("name") final String name) throws Exception { @PathParam("name") final String name) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal(); final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("==================================================="); // logger.info("===================================================");
LOGGER.info("== DATA retrieveDataFull ? id={} user={}", uuid, (gc == null ? "null" : gc.userByToken)); LOGGER.info("== DATA retrieveDataFull ? id={} user={}", oid, (gc == null ? "null" : gc.userByToken));
// logger.info("==================================================="); // logger.info("===================================================");
final Data value = getSmall(uuid); final Data value = getSmall(oid);
if (value == null) { if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + uuid).type("text/plain").build(); return Response.status(404).entity("media NOT FOUND: " + oid).type("text/plain").build();
} }
return buildStream(getFileData(uuid), range, return buildStream(getFileData(oid), range,
value.mimeType == null ? "application/octet-stream" : value.mimeType); value.mimeType == null ? "application/octet-stream" : value.mimeType);
} }
@ -502,7 +502,7 @@ public class DataResource {
} }
} }
public static void undelete(final Long id) throws Exception { public void undelete(final Long id) throws Exception {
DataAccess.unsetDelete(Data.class, id); DataAccess.unsetDelete(Data.class, id);
} }

View File

@ -0,0 +1,14 @@
package org.kar.archidata.converter.jackson;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class JacksonModules {
public static SimpleModule getAllModules() {
final SimpleModule module = new SimpleModule();
module.addSerializer(ObjectId.class, new ObjectIdSerializer());
module.addDeserializer(ObjectId.class, new ObjectIdDeserializer());
return module;
}
}

View File

@ -0,0 +1,16 @@
package org.kar.archidata.converter.jackson;
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class ObjectIdDeserializer extends JsonDeserializer<ObjectId> {
@Override
public ObjectId deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
return new ObjectId(p.getValueAsString());
}
}

View File

@ -0,0 +1,17 @@
package org.kar.archidata.converter.jackson;
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
@Override
public void serialize(final ObjectId value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeString(value.toHexString());
}
}

View File

@ -0,0 +1,34 @@
package org.kar.archidata.converter.morphia;
import java.sql.Timestamp;
import org.bson.BsonReader;
import org.bson.BsonType;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
public class SqlTimestampCodec implements Codec<Timestamp> {
@Override
public void encode(
final BsonWriter writer,
final Timestamp value,
final org.bson.codecs.EncoderContext encoderContext) {
writer.writeDateTime(value.getTime());
}
@Override
public Timestamp decode(final BsonReader reader, final org.bson.codecs.DecoderContext decoderContext) {
final BsonType bsonType = reader.getCurrentBsonType();
if (bsonType == BsonType.DATE_TIME) {
return new Timestamp(reader.readDateTime());
} else {
throw new IllegalArgumentException("Expected a DATE_TIME but found " + bsonType);
}
}
@Override
public Class<Timestamp> getEncoderClass() {
return Timestamp.class;
}
}

View File

@ -0,0 +1,350 @@
package org.kar.archidata.dataAccess;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.dataAccess.options.TransmitKey;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DbIo;
import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.db.DbIoMorphia;
import org.kar.archidata.db.DbIoSql;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.InternalServerErrorException;
/* TODO list:
- Manage to group of SQL action to permit to commit only at the end.
*/
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
* back-end. */
public abstract class DBAccess implements Closeable {
final static Logger LOGGER = LoggerFactory.getLogger(DBAccess.class);
public static final DBAccess createInterface()
throws InternalServerErrorException, IOException, DataAccessException {
return DBAccess.createInterface(DbIoFactory.create());
}
public static final DBAccess createInterface(final DbConfig config)
throws InternalServerErrorException, IOException {
return DBAccess.createInterface(DbIoFactory.create(config));
}
public static final DBAccess createInterface(final DbIo io) throws InternalServerErrorException {
if (io instanceof final DbIoMorphia ioMorphia) {
try {
return new DBAccessMorphia(ioMorphia);
} catch (final IOException e) {
e.printStackTrace();
throw new InternalServerErrorException("Fail to create DB interface.");
}
} else if (io instanceof final DbIoSql ioSQL) {
try {
return new DBAccessSQL(ioSQL);
} catch (final IOException e) {
e.printStackTrace();
throw new InternalServerErrorException("Fail to create DB interface.");
}
}
throw new InternalServerErrorException("unknow DB interface ... ");
}
public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public boolean createDB(final String name) {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public boolean deleteDB(final String name) {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public <ID_TYPE> QueryCondition getTableIdCondition(
final Class<?> clazz,
final ID_TYPE idKey,
final QueryOptions options) throws DataAccessException {
// Find the ID field type ....
final Field idField = AnnotationTools.getIdField(clazz);
if (idField == null) {
throw new DataAccessException(
"The class have no annotation @Id ==> can not determine the default type searching");
}
// check the compatibility of the id and the declared ID
Class<?> typeClass = idField.getType();
if (idKey == null) {
throw new DataAccessException("Try to identify the ID type and object was null.");
}
final FieldName fieldName = AnnotationTools.getFieldName(idField, options);
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
if (typeClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(fieldName.inStruct())) {
typeClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing ... '{}' => '{}'", typeClass.getCanonicalName(),
specify.clazz.getCanonicalName());
break;
}
}
}
if (idKey.getClass() != typeClass) {
if (idKey.getClass() == Condition.class) {
throw new DataAccessException(
"Try to identify the ID type on a condition 'close' internal API error use xxxWhere(...) instead.");
}
throw new DataAccessException("Request update with the wrong type ...");
}
return new QueryCondition(fieldName.inTable(), "=", idKey);
}
// TODO: manage insert batch...
public <T> List<T> insertMultiple(final List<T> data, final QueryOption... options) throws Exception {
final List<T> out = new ArrayList<>();
for (final T elem : data) {
final T tmp = insert(elem, options);
out.add(tmp);
}
return out;
}
abstract public <T> T insert(final T data, final QueryOption... option) throws Exception;
// seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated...
public <T> T insertWithJson(final Class<T> clazz, final String jsonData) throws Exception {
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
// parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz);
return insert(data);
}
/** Update an object with the inserted json data
*
* @param <T> Type of the object to insert
* @param <ID_TYPE> Master key on the object manage with @Id
* @param clazz Class reference of the insertion model
* @param id Key to insert data
* @param jsonData Json data (partial) values to update
* @return the number of object updated
* @throws Exception */
public <T, ID_TYPE> long updateWithJson(
final Class<T> clazz,
final ID_TYPE id,
final String jsonData,
final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
options.add(new TransmitKey(id));
return updateWhereWithJson(clazz, jsonData, options.getAllArray());
}
public <T> long updateWhereWithJson(final Class<T> clazz, final String jsonData, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
if (options.get(Condition.class).size() == 0) {
throw new DataAccessException("request a updateWhereWithJson without any condition");
}
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
// 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<String> keys = new ArrayList<>();
final var iterator = root.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
options.add(new FilterValue(keys));
return updateWhere(data, options.getAllArray());
}
public <T, ID_TYPE> long update(final T data, final ID_TYPE id) throws Exception {
return update(data, id, AnnotationTools.getFieldsNames(data.getClass()));
}
/** @param <T>
* @param data
* @param id
* @param filterValue
* @return the affected rows.
* @throws Exception */
public <T, ID_TYPE> long update(
final T data,
final ID_TYPE id,
final List<String> updateColomn,
final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(data.getClass(), id, options)));
options.add(new FilterValue(updateColomn));
options.add(new TransmitKey(id));
return updateWhere(data, options);
}
public <T> long updateWhere(final T data, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return updateWhere(data, options);
}
public abstract <T> long updateWhere(final T data, QueryOptions options) throws Exception;
public <T> T getWhere(final Class<T> clazz, final QueryOptions options) throws Exception {
options.add(new Limit(1));
final List<T> values = getsWhere(clazz, options);
if (values.size() == 0) {
return null;
}
return values.get(0);
}
public <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return getWhere(clazz, options);
}
public <T> List<T> getsWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return getsWhere(clazz, options);
}
public Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty)
throws DataAccessException {
if (options == null) {
return new Condition();
}
final List<Condition> conditions = options.get(Condition.class);
if (conditions.size() == 0) {
if (throwIfEmpty) {
throw new DataAccessException("request a gets without any condition");
} else {
return new Condition();
}
}
Condition condition = null;
if (conditions.size() == 1) {
condition = conditions.get(0);
} else {
final QueryAnd andCondition = new QueryAnd();
for (final Condition cond : conditions) {
andCondition.add(cond.condition);
}
condition = new Condition(andCondition);
}
return condition;
}
abstract public <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options)
throws DataAccessException, IOException;
public <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return countWhere(clazz, options);
}
public long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return countWhere(clazz, options);
}
public abstract long countWhere(final Class<?> clazz, final QueryOptions options) throws Exception;
public <T, ID_TYPE> T get(final Class<T> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return getWhere(clazz, options.getAllArray());
}
public <T> List<T> gets(final Class<T> clazz) throws Exception {
return getsWhere(clazz);
}
public <T> List<T> gets(final Class<T> clazz, final QueryOption... option) throws Exception {
return getsWhere(clazz, option);
}
/** Delete items with the specific Id (cf @Id) and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
* @param <ID_TYPE> Type of the reference @Id
* @param clazz Data model that might remove element
* @param id Unique Id of the model
* @param options (Optional) Options of the request
* @return Number of element that is removed. */
public <ID_TYPE> long delete(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (hasDeletedFieldName != null) {
return deleteSoft(clazz, id, options);
} else {
return deleteHard(clazz, id, options);
}
}
/** Delete items with the specific condition and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
* @param clazz Data model that might remove element.
* @param condition Condition to remove elements.
* @param options (Optional) Options of the request.
* @return Number of element that is removed. */
public long deleteWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (hasDeletedFieldName != null) {
return deleteSoftWhere(clazz, option);
} else {
return deleteHardWhere(clazz, option);
}
}
public <ID_TYPE> long deleteHard(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteHardWhere(clazz, options.getAllArray());
}
public abstract long deleteHardWhere(final Class<?> clazz, final QueryOption... option) throws Exception;
public <ID_TYPE> long deleteSoft(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteSoftWhere(clazz, options.getAllArray());
}
public abstract long deleteSoftWhere(final Class<?> clazz, final QueryOption... option) throws Exception;
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id) throws DataAccessException {
return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id, new QueryOptions())));
}
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws DataAccessException {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return unsetDeleteWhere(clazz, options.getAllArray());
}
public abstract long unsetDeleteWhere(final Class<?> clazz, final QueryOption... option) throws DataAccessException;
public abstract void drop(final Class<?> clazz, final QueryOption... option) throws Exception;
public abstract void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception;
}

View File

@ -0,0 +1,947 @@
package org.kar.archidata.dataAccess;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOnMongo.AddOnManyToOne;
import org.kar.archidata.dataAccess.addOnMongo.AddOnOneToMany;
import org.kar.archidata.dataAccess.addOnMongo.DataAccessAddOn;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.db.DbIoMorphia;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.UuidUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.ReturnDocument;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.client.result.UpdateResult;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.InternalServerErrorException;
/* TODO list:
- Manage to group of SQL action to permit to commit only at the end.
*/
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
* back-end. */
public class DBAccessMorphia extends DBAccess {
static final Logger LOGGER = LoggerFactory.getLogger(DBAccessMorphia.class);
// by default we manage some add-on that permit to manage non-native model (like json serialization, List of external key as String list...)
static final List<DataAccessAddOn> addOn = new ArrayList<>();
static {
//addOn.add(new AddOnManyToMany());
addOn.add(new AddOnManyToOne());
addOn.add(new AddOnOneToMany());
// no need, native support in mango .... addOn.add(new AddOnDataJson());
}
/** Add a new add-on on the current management.
* @param addOn instantiate object on the Add-on
*/
public static void addAddOn(final DataAccessAddOn addOn) {
DBAccessMorphia.addOn.add(addOn);
}
private final DbIoMorphia db;
public DBAccessMorphia(final DbIoMorphia db) throws IOException {
this.db = db;
db.open();
}
@Override
public void close() throws IOException {
this.db.close();
}
public DbIoMorphia getInterface() {
return this.db;
}
@Override
public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException {
// in Mongo DB we do not need to create a DB, then we have no need to check if it exist
return true;
}
@Override
public boolean createDB(final String name) {
// in Mongo DB we do not need to create a DB
return true;
}
@Override
public boolean deleteDB(final String name) {
final MongoDatabase database = this.db.getClient().getDatabase(name);
database.drop();
return true;
}
@Override
public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException {
return true;
}
public byte[][] splitIntoGroupsOf16Bytes(final byte[] input) {
final int inputLength = input.length;
final int numOfGroups = (inputLength + 15) / 16; // Calculate the number of groups needed
final byte[][] groups = new byte[numOfGroups][16];
for (int i = 0; i < numOfGroups; i++) {
final int startIndex = i * 16;
final int endIndex = Math.min(startIndex + 16, inputLength);
groups[i] = Arrays.copyOfRange(input, startIndex, endIndex);
}
return groups;
}
protected <T> void setValuedb(
final Class<?> type,
final T data,
final Field field,
final String fieldName,
final Document docSet,
final Document docUnSet) throws Exception {
if (field.get(data) == null) {
docUnSet.append(fieldName, "");
return;
}
if (type == long.class) {
docSet.append(fieldName, field.getLong(data));
return;
}
if (type == int.class) {
docSet.append(fieldName, field.getInt(data));
return;
}
if (type == float.class) {
docSet.append(fieldName, field.getFloat(data));
return;
}
if (type == Double.class) {
docSet.append(fieldName, field.getDouble(data));
return;
}
if (type == boolean.class) {
docSet.append(fieldName, field.getBoolean(data));
return;
}
final Object tmp = field.get(data);
if (tmp == null) {
docUnSet.append(fieldName, "");
return;
}
if (type.isEnum()) {
docSet.append(fieldName, tmp.toString());
return;
}
if (type == Long.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Integer.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Float.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Double.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Boolean.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == String.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Timestamp.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == UUID.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Date.class) {
// TODO ...
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant());
ps.setTimestamp(iii.value, sqlDate);
}*/
}
if (type == Instant.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final String sqlDate = ((Instant) tmp).toString();
ps.setString(iii.value, sqlDate);
}
*/
}
if (type == LocalDate.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Date sqlDate = java.sql.Date.valueOf((LocalDate) tmp);
ps.setDate(iii.value, sqlDate);
}
*/
}
if (type == LocalTime.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Time sqlDate = java.sql.Time.valueOf((LocalTime) tmp);
ps.setTime(iii.value, sqlDate);
}
*/
}
throw new DataAccessException("Unknown Field Type");
}
public <T> void setValueFromDoc(
final Class<?> type,
final Object data,
final Field field,
final Document doc,
final List<LazyGetter> lazyCall,
final QueryOptions options) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
if (!doc.containsKey(fieldName)) {
field.set(data, null);
return;
}
if (type == UUID.class) {
final UUID value = doc.get(fieldName, UUID.class);
field.set(data, value);
return;
}
if (type == Long.class || type == long.class) {
final Long value = doc.getLong(fieldName);
field.set(data, value);
return;
}
if (type == Integer.class || type == int.class) {
final Integer value = doc.getInteger(fieldName);
field.set(data, value);
return;
}
if (type == Float.class || type == float.class) {
final Double value = doc.getDouble(fieldName);
field.set(data, (float) ((double) value));
return;
}
if (type == Double.class || type == double.class) {
final Double value = doc.getDouble(fieldName);
field.set(data, value);
return;
}
if (type == Boolean.class || type == boolean.class) {
final Boolean value = doc.getBoolean(fieldName);
field.set(data, value);
return;
}
if (type == Timestamp.class) {
final Date value = doc.get(fieldName, Date.class);
final Timestamp newData = new Timestamp(value.getTime());
field.set(data, newData);
return;
}
if (type == Date.class) {
final Date value = doc.get(fieldName, Date.class);
field.set(data, value);
return;
}
if (type == Instant.class) {
final Date value = doc.get(fieldName, Date.class);
final Instant newData = value.toInstant();
field.set(data, newData);
return;
}
if (type == LocalDate.class) {
final Date value = doc.get(fieldName, Date.class);
final LocalDate newData = value.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
field.set(data, newData);
return;
}
if (type == LocalTime.class) {
final Long value = doc.getLong(fieldName);
final LocalTime newData = LocalTime.ofNanoOfDay(value);
field.set(data, newData);
return;
}
if (type == String.class) {
final String value = doc.getString(fieldName);
field.set(data, value);
return;
}
if (type == UUID.class) {
final Object value = doc.get(fieldName, field.getType());
field.set(data, value);
return;
}
if (type.isEnum()) {
final String value = doc.getString(fieldName);
boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(value)) {
field.set(data, elem);
find = true;
break;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + value + "'");
}
return;
}
if (List.class == field.getType()) {
final Object value = doc.get(fieldName, field.getType());
field.set(data, value);
} else {
final Object value = createObjectFromDocument(doc.get(fieldName, Document.class), field.getType(), null,
lazyCall);
field.set(data, value);
}
return;
//throw new ArchiveException("wrong type of field [" + fieldName + "]: " + doc.toJson());
}
protected Object convertDefaultField(String data, final Field field) throws Exception {
if (data.startsWith("'") && data.endsWith("'")) {
data = data.substring(1, data.length() - 1);
}
final Class<?> type = field.getType();
if (type == UUID.class) {
}
if (type == Long.class || type == long.class) {
return Long.parseLong(data);
}
if (type == Integer.class || type == int.class) {
return Integer.parseInt(data);
}
if (type == Float.class || type == float.class) {
return Float.parseFloat(data);
}
if (type == Double.class || type == double.class) {
return Double.parseDouble(data);
}
if (type == Boolean.class || type == boolean.class) {
return Boolean.parseBoolean(data);
}
if (type == Timestamp.class) {}
if (type == Date.class) {}
if (type == Instant.class) {}
if (type == LocalDate.class) {}
if (type == LocalTime.class) {}
if (type == String.class) {}
if (type.isEnum()) {
final boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(data)) {
return elem;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + data + "'");
}
}
LOGGER.warn("Request default of unknow native type {} => {}", type.getCanonicalName(), data);
return null;
}
public boolean isAddOnField(final Field field) {
return findAddOnforField(field) != null;
}
public DataAccessAddOn findAddOnforField(final Field field) {
for (final DataAccessAddOn elem : addOn) {
if (elem.isCompatibleField(field)) {
return elem;
}
}
return null;
}
public long getNextSequenceLongValue(final String collectionName, String fieldName) {
if (fieldName == null || fieldName.isEmpty()) {
fieldName = "sequence_id";
}
// Collection "counters" to store the sequences if Ids
final MongoCollection<Document> countersCollection = this.db.getDatastore().getDatabase()
.getCollection("counters");
// Filter to find the specific counter for the collections
final Document filter = new Document("_id", collectionName);
// Update the field <fieldName> of 1
final Document update = new Document("$inc", new Document(fieldName, 1L));
// get the value after updated it
final FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
.upsert(true); // create field if not exist
// Real creation of the unique counter.
final Document updatedCounter = countersCollection.findOneAndUpdate(filter, update, options);
// Return the new sequence value...
return updatedCounter.getLong(fieldName);
}
@Override
@SuppressWarnings("unchecked")
public <T> T insert(final T data, final QueryOption... option) throws Exception {
final Class<?> clazz = data.getClass();
final QueryOptions options = new QueryOptions(option);
// External checker of data:
final List<CheckFunction> checks = options.get(CheckFunction.class);
for (final CheckFunction check : checks) {
check.getChecker().check(this, "", data, AnnotationTools.getFieldsNames(clazz), options);
}
final List<Field> asyncFieldUpdate = new ArrayList<>();
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
Field primaryKeyField = null;
Object uniqueId = null;
// real add in the BDD:
ObjectId insertedId = null;
try {
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase()
.getCollection(collectionName);
final Document doc = new Document();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final String tableFieldName = AnnotationTools.getFieldName(field, options).inTable();
Object currentInsertValue = field.get(data);
if (AnnotationTools.isPrimaryKey(field)) {
primaryKeyField = field;
if (primaryKeyField.getType() == UUID.class) {
final UUID uuid = UuidUtils.nextUUID();
uniqueId = uuid;
doc.append(tableFieldName, uuid);
continue;
} else if (primaryKeyField.getType() == Long.class || primaryKeyField.getType() == long.class) {
// By default the MongoDB does not manage the
final long id = getNextSequenceLongValue(collectionName, tableFieldName);
uniqueId = id;
doc.append(tableFieldName, id);
continue;
}
LOGGER.error("TODO: Manage the ID primary key for type: ");
continue;
}
final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null && !addOn.canInsert(field)) {
if (addOn.isInsertAsync(field)) {
LOGGER.error("TODO: add async objects ...");
//asyncFieldUpdate.add(field);
}
continue;
}
final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
if (createTime) {
doc.append(tableFieldName, Date.from(Instant.now()));
continue;
}
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
doc.append(tableFieldName, Date.from(Instant.now()));
continue;
}
if (currentInsertValue == null && !field.getClass().isPrimitive()) {
final DefaultValue[] defaultValue = field.getDeclaredAnnotationsByType(DefaultValue.class);
LOGGER.error("TODO: convert default value in the correct value for the DB...");
if (defaultValue.length == 0) {
continue;
} else {
final String value = defaultValue[0].value();
if (value == null) {
continue;
}
currentInsertValue = convertDefaultField(value, field);
}
}
doc.append(tableFieldName, currentInsertValue);
}
final InsertOneResult result = collection.insertOne(doc);
// Get the Object of inserted object:
insertedId = result.getInsertedId().asObjectId().getValue();
LOGGER.info("Document inserted with ID: " + insertedId);
// Rechercher et récupérer le document inséré à partir de son ObjectId
final Document insertedDocument = collection.find(new Document("_id", insertedId)).first();
// Afficher le document récupéré
LOGGER.trace("Inserted document: " + insertedDocument);
} catch (final Exception ex) {
LOGGER.error("Fail SQL request: {}", ex.getMessage());
ex.printStackTrace();
throw new DataAccessException("Fail to Insert data in DB : " + ex.getMessage());
}
final List<LazyGetter> asyncActions = new ArrayList<>();
for (final Field field : asyncFieldUpdate) {
final DataAccessAddOn addOn = findAddOnforField(field);
if (uniqueId instanceof final Long id) {
LOGGER.error("TODO: Add on not managed .1. ");
//addOn.asyncInsert(tableName, id, field, field.get(data), asyncActions);
} else if (uniqueId instanceof final UUID uuid) {
LOGGER.error("TODO: Add on not managed .2. ");
//addOn.asyncInsert(tableName, uuid, field, field.get(data), asyncActions);
}
}
for (final LazyGetter action : asyncActions) {
action.doRequest();
}
return (T) getWhere(clazz, new Condition(new QueryCondition("_id", "=", insertedId)));
}
@Override
public <T> long updateWhere(final T data, QueryOptions options) throws Exception {
final Class<?> clazz = data.getClass();
if (options == null) {
options = new QueryOptions();
}
final Condition condition = conditionFusionOrEmpty(options, true);
final List<FilterValue> filterKeys = options != null ? options.get(FilterValue.class) : new ArrayList<>();
if (filterKeys.size() != 1) {
throw new DataAccessException("request a gets without/or with more 1 filter of values");
}
final FilterValue filterKey = filterKeys.get(0);
// External checker of data:
if (options != null) {
final List<CheckFunction> checks = options.get(CheckFunction.class);
for (final CheckFunction check : checks) {
check.getChecker().check(this, "", data, filterKey.getValues(), options);
}
}
final List<LazyGetter> asyncActions = new ArrayList<>();
// real add in the BDD:
try {
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
final Document docSet = new Document();
final Document docUnSet = new Document();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
// update field is not conditioned by filter:
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
docSet.append(fieldName, Date.from(Instant.now()));
continue;
}
if (!filterKey.getValues().contains(fieldName)) {
continue;
} else if (AnnotationTools.isGenericField(field)) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null && !addOn.canInsert(field)) {
if (addOn.isInsertAsync(field)) {
LOGGER.error("TODO: Add on not managed .3. ");
/*
final List<TransmitKey> transmitKey = options.get(TransmitKey.class);
if (transmitKey.size() != 1) {
throw new DataAccessException(
"Fail to transmit Key to update the async update... (must have only 1)");
}
addOn.asyncUpdate(tableName, transmitKey.get(0).getKey(), field, field.get(data), asyncActions);
*/
}
continue;
}
if (addOn != null) {
addOn.insertData(this, field, data, options, docSet, docUnSet);
} else {
final Class<?> type = field.getType();
if (!type.isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) {
continue;
}
}
setValuedb(type, data, field, fieldName, docSet, docUnSet);
}
}
// Do the query ...
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase()
.getCollection(collectionName);
final Document actions = new Document();
if (!docSet.isEmpty()) {
actions.append("$set", docSet);
}
if (!docUnSet.isEmpty()) {
actions.append("$unset", docUnSet);
}
LOGGER.info("updateWhere with value: {}", actions.toJson());
final UpdateResult ret = collection.updateMany(filters, actions);
return ret.getModifiedCount();
} catch (final Exception ex) {
ex.printStackTrace();
}
for (final LazyGetter action : asyncActions) {
action.doRequest();
}
return 0;
}
public List<String> generateSelectField(final Class<?> clazz, final QueryOptions options) throws Exception {
// TODO: list of user select fields.
final boolean readAllfields = QueryOptions.readAllColomn(options);
final List<String> fieldsName = new ArrayList<>();
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 DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
final String name = AnnotationTools.getFieldName(elem, options).inTable();
fieldsName.add(name);
}
return fieldsName;
}
@Override
public Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty)
throws DataAccessException {
if (options == null) {
return new Condition();
}
final List<Condition> conditions = options.get(Condition.class);
if (conditions.size() == 0) {
if (throwIfEmpty) {
throw new DataAccessException("request a gets without any condition");
} else {
return new Condition();
}
}
Condition condition = null;
if (conditions.size() == 1) {
condition = conditions.get(0);
} else {
final QueryAnd andCondition = new QueryAnd();
for (final Condition cond : conditions) {
andCondition.add(cond.condition);
}
condition = new Condition(andCondition);
}
return condition;
}
@Override
@SuppressWarnings("unchecked")
public <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options)
throws DataAccessException, IOException {
final Condition condition = conditionFusionOrEmpty(options, false);
final List<LazyGetter> lazyCall = new ArrayList<>();
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final List<T> outs = new ArrayList<>();
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
try {
// Generate the filtering of the data:
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
FindIterable<Document> retFind = null;
if (filters != null) {
//LOGGER.info("getsWhere Find filter: {}", filters.toBsonDocument().toJson());
retFind = collection.find(filters);
} else {
retFind = collection.find();
}
/* Not manage right now ...
final List<GroupBy> groups = options.get(GroupBy.class);
for (final GroupBy group : groups) {
group.generateQuery(query, tableName);
}
*/
final List<OrderBy> orders = options.get(OrderBy.class);
if (orders.size() != 0) {
final Document sorts = new Document();
for (final OrderBy order : orders) {
order.generateSort(sorts);
}
retFind = retFind.sort(sorts);
}
final List<Limit> limits = options.get(Limit.class);
if (limits.size() == 1) {
retFind = retFind.limit((int) limits.get(0).getValue());
} else if (limits.size() > 1) {
throw new DataAccessException("Request with multiple 'limit'...");
}
// Select values to read
final List<String> listFields = generateSelectField(clazz, options);
listFields.add("_id");
retFind = retFind.projection(Projections.include(listFields.toArray(new String[0])));
LOGGER.info("GetsWhere ...");
final MongoCursor<Document> cursor = retFind.iterator();
try (cursor) {
while (cursor.hasNext()) {
final Document doc = cursor.next();
LOGGER.info(" - getWhere value: {}", doc.toJson());
final Object data = createObjectFromDocument(doc, clazz, options, lazyCall);
final T out = (T) data;
outs.add(out);
}
LOGGER.info("Async calls: {}", lazyCall.size());
for (final LazyGetter elem : lazyCall) {
elem.doRequest();
}
}
} catch (final Exception ex) {
ex.printStackTrace();
throw new DataAccessException("Catch an Exception: " + ex.getMessage());
}
return outs;
}
public Object createObjectFromDocument(
final Document doc,
final Class<?> clazz,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final boolean readAllfields = QueryOptions.readAllColomn(options);
// TODO: manage class that is defined inside a class ==> Not manage for now...
Object data = null;
for (final Constructor<?> contructor : clazz.getConstructors()) {
if (contructor.getParameterCount() == 0) {
data = contructor.newInstance();
break;
}
}
if (data == null) {
throw new DataAccessException(
"Can not find the default constructor for the class: " + clazz.getCanonicalName());
}
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 DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
if (addOn != null) {
LOGGER.error("TODO: Add on not managed .6. ");
addOn.fillFromDoc(this, doc, elem, data, options, lazyCall);
} else {
setValueFromDoc(elem.getType(), data, elem, doc, lazyCall, options);
}
}
return data;
}
@Override
public <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return this.countWhere(clazz, options);
}
@Override
public long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return countWhere(clazz, options);
}
@Override
public long countWhere(final Class<?> clazz, final QueryOptions options) throws Exception {
final Condition condition = conditionFusionOrEmpty(options, false);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
try {
// Generate the filtering of the data:
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
if (filters != null) {
return collection.countDocuments(filters);
}
return collection.countDocuments();
} catch (final Exception ex) {
ex.printStackTrace();
throw new DataAccessException("Catch an Exception: " + ex.getMessage());
}
}
@Override
public <T, ID_TYPE> T get(final Class<T> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return this.getWhere(clazz, options.getAllArray());
}
@Override
public <ID_TYPE> long deleteHard(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteHardWhere(clazz, options.getAllArray());
}
@Override
public long deleteHardWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final Condition condition = conditionFusionOrEmpty(options, true);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
DeleteResult retFind;
if (filters != null) {
retFind = collection.deleteMany(filters);
} else {
throw new DataAccessException("Too dangerout to delete element with no filter values !!!");
}
return retFind.getDeletedCount();
}
@Override
public <ID_TYPE> long deleteSoft(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteSoftWhere(clazz, options.getAllArray());
}
@Override
public long deleteSoftWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final Condition condition = conditionFusionOrEmpty(options, true);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
final Document actions = new Document("$set", new Document(deletedFieldName, true));
LOGGER.info("update some values: {}", actions.toJson());
final UpdateResult ret = collection.updateMany(filters, actions);
return ret.getModifiedCount();
}
@Override
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id) throws DataAccessException {
return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id, new QueryOptions())));
}
@Override
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws DataAccessException {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return unsetDeleteWhere(clazz, options.getAllArray());
}
@Override
public long unsetDeleteWhere(final Class<?> clazz, final QueryOption... option) throws DataAccessException {
final QueryOptions options = new QueryOptions(option);
final Condition condition = conditionFusionOrEmpty(options, true);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (deletedFieldName == null) {
throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field");
}
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
final Document actions = new Document("$set", new Document(deletedFieldName, false));
LOGGER.info("update some values: {}", actions.toJson());
final UpdateResult ret = collection.updateMany(filters, actions);
return ret.getModifiedCount();
}
@Override
public void drop(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
collection.drop();
}
@Override
public void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
collection.deleteMany(new Document());
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,13 +19,12 @@ import java.util.UUID;
import org.kar.archidata.dataAccess.exportTools.TableQuery; import org.kar.archidata.dataAccess.exportTools.TableQuery;
import org.kar.archidata.dataAccess.exportTools.TableQueryTypes; import org.kar.archidata.dataAccess.exportTools.TableQueryTypes;
import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.DBInterfaceOption;
import org.kar.archidata.dataAccess.options.GroupBy; import org.kar.archidata.dataAccess.options.GroupBy;
import org.kar.archidata.dataAccess.options.Limit; import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OrderBy; import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption; import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.archidata.tools.DateTools; import org.kar.archidata.tools.DateTools;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -246,24 +245,24 @@ public class DataExport {
} }
public static TableQuery queryTable( public static TableQuery queryTable(
final DBAccessSQL ioDb,
final List<TableQueryTypes> headers, final List<TableQueryTypes> headers,
final String query, final String query,
final List<Object> parameters, final List<Object> parameters,
final QueryOption... option) throws Exception { final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option); final QueryOptions options = new QueryOptions(option);
return queryTable(headers, query, parameters, options); return queryTable(ioDb, headers, query, parameters, options);
} }
public static TableQuery queryTable( public static TableQuery queryTable(
final DBAccessSQL ioDb,
final List<TableQueryTypes> headers, final List<TableQueryTypes> headers,
final String queryBase, final String queryBase,
final List<Object> parameters, final List<Object> parameters,
final QueryOptions options) throws Exception { final QueryOptions options) throws Exception {
final List<LazyGetter> lazyCall = new ArrayList<>(); final List<LazyGetter> lazyCall = new ArrayList<>();
// TODO ... final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final DBEntry entry = DBInterfaceOption.getAutoEntry(options);
final Condition condition = DataAccess.conditionFusionOrEmpty(options, false); final Condition condition = ioDb.conditionFusionOrEmpty(options, false);
final StringBuilder query = new StringBuilder(queryBase); final StringBuilder query = new StringBuilder(queryBase);
final TableQuery out = new TableQuery(headers); final TableQuery out = new TableQuery(headers);
// real add in the BDD: // real add in the BDD:
@ -286,18 +285,18 @@ public class DataExport {
} }
LOGGER.warn("generate the query: '{}'", query.toString()); LOGGER.warn("generate the query: '{}'", query.toString());
// prepare the request: // prepare the request:
final PreparedStatement ps = entry.connection.prepareStatement(query.toString(), final PreparedStatement ps = ioDb.getConnection().prepareStatement(query.toString(),
Statement.RETURN_GENERATED_KEYS); Statement.RETURN_GENERATED_KEYS);
final CountInOut iii = new CountInOut(1); final CountInOut iii = new CountInOut(1);
if (parameters != null) { if (parameters != null) {
for (final Object elem : parameters) { for (final Object elem : parameters) {
DataAccess.addElement(ps, elem, iii); ioDb.addElement(ps, elem, iii);
} }
iii.inc(); iii.inc();
} }
condition.injectQuery(ps, iii); condition.injectQuery(ioDb, ps, iii);
if (limits.size() == 1) { if (limits.size() == 1) {
limits.get(0).injectQuery(ps, iii); limits.get(0).injectQuery(ioDb, ps, iii);
} }
// execute the request // execute the request
final ResultSet rs = ps.executeQuery(); final ResultSet rs = ps.executeQuery();
@ -332,8 +331,6 @@ public class DataExport {
throw ex; throw ex;
} catch (final Exception ex) { } catch (final Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} finally {
entry.close();
} }
return out; return out;
} }
@ -395,7 +392,7 @@ public class DataExport {
} }
if (MediaType.APPLICATION_JSON.equals(accept)) { if (MediaType.APPLICATION_JSON.equals(accept)) {
LOGGER.info("Start mapping josn"); LOGGER.info("Start mapping josn");
final ObjectMapper objectMapper = new ObjectMapper(); final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
LOGGER.info("Start find modules josn"); LOGGER.info("Start find modules josn");
objectMapper.findAndRegisterModules(); objectMapper.findAndRegisterModules();
LOGGER.info("Start map object"); LOGGER.info("Start map object");

View File

@ -10,11 +10,14 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp; import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.DataIfNotExists; import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.UpdateTimestamp; import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOnSQL.DataAccessAddOn;
import org.kar.archidata.dataAccess.options.CreateDropTable; import org.kar.archidata.dataAccess.options.CreateDropTable;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -25,13 +28,17 @@ import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.GenerationType; import jakarta.persistence.GenerationType;
public class DataFactory { public class DataFactory {
static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class); private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class);
public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws DataAccessException { public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws DataAccessException {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { final String typelocal = ConfigBaseVariable.getDBType();
if ("mysql".equals(typelocal)) {
if (type == UUID.class) { if (type == UUID.class) {
return "binary(16)"; return "binary(16)";
} }
if (type == ObjectId.class) {
return "binary(12)";
}
if (type == Long.class || type == long.class) { if (type == Long.class || type == long.class) {
return "bigint"; return "bigint";
} }
@ -82,10 +89,13 @@ public class DataFactory {
out.append(")"); out.append(")");
return out.toString(); return out.toString();
} }
} else { } else if ("sqlite".equals(typelocal)) {
if (type == UUID.class) { if (type == UUID.class) {
return "BINARY(16)"; return "BINARY(16)";
} }
if (type == ObjectId.class) {
return "BINARY(12)";
}
if (type == Long.class || type == long.class) { if (type == Long.class || type == long.class) {
return "INTEGER"; return "INTEGER";
} }
@ -138,6 +148,9 @@ public class DataFactory {
out.append(" ) )"); out.append(" ) )");
return out.toString(); return out.toString();
} }
} else if ("mongo".equals(typelocal)) {
// no importance for mango ...
return "text";
} }
throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName()); throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName());
} }
@ -152,8 +165,9 @@ public class DataFactory {
final boolean createIfNotExist, final boolean createIfNotExist,
final boolean createDrop, final boolean createDrop,
final int fieldId, final int fieldId,
final Class<?> classModel) throws Exception { final Class<?> classModel,
final String name = AnnotationTools.getFieldName(elem); final QueryOptions options) throws Exception {
final String name = AnnotationTools.getFieldName(elem, options).inTable();
final int limitSize = AnnotationTools.getLimitSize(elem); final int limitSize = AnnotationTools.getLimitSize(elem);
final boolean notNull = AnnotationTools.getColumnNotNull(elem); final boolean notNull = AnnotationTools.getColumnNotNull(elem);
@ -162,7 +176,7 @@ public class DataFactory {
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0; final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
final String comment = AnnotationTools.getComment(elem); final String comment = AnnotationTools.getSchemaDescription(elem);
final String defaultValue = AnnotationTools.getDefault(elem); final String defaultValue = AnnotationTools.getDefault(elem);
if (mainTableBuilder.toString().length() == 0) { if (mainTableBuilder.toString().length() == 0) {
@ -299,7 +313,10 @@ public class DataFactory {
} }
} }
private static boolean isFieldFromSuperClass(final Class<?> model, final String filedName) { private static boolean isFieldFromSuperClass(
final Class<?> model,
final String filedName,
final QueryOptions options) {
final Class<?> superClass = model.getSuperclass(); final Class<?> superClass = model.getSuperclass();
if (superClass == null) { if (superClass == null) {
return false; return false;
@ -307,7 +324,7 @@ public class DataFactory {
for (final Field field : superClass.getFields()) { for (final Field field : superClass.getFields()) {
String name; String name;
try { try {
name = AnnotationTools.getFieldName(field); name = AnnotationTools.getFieldName(field, options).inTable();
if (filedName.equals(name)) { if (filedName.equals(name)) {
return true; return true;
} }
@ -355,7 +372,7 @@ public class DataFactory {
for (final Field elem : clazz.getFields()) { for (final Field elem : clazz.getFields()) {
// DEtect the primary key (support only one primary key right now... // DEtect the primary key (support only one primary key right now...
if (AnnotationTools.isPrimaryKey(elem)) { if (AnnotationTools.isPrimaryKey(elem)) {
primaryKeys.add(AnnotationTools.getFieldName(elem)); primaryKeys.add(AnnotationTools.getFieldName(elem, options).inTable());
} }
} }
// Here we insert the data in the reverse mode ==> the parent class add there parameter at the start (we reorder the field with the parenting). // Here we insert the data in the reverse mode ==> the parent class add there parameter at the start (we reorder the field with the parenting).
@ -372,8 +389,8 @@ public class DataFactory {
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue; continue;
} }
final String dataName = AnnotationTools.getFieldName(elem); final String dataName = AnnotationTools.getFieldName(elem, options).inTable();
if (isFieldFromSuperClass(currentClazz, dataName)) { if (isFieldFromSuperClass(currentClazz, dataName, options)) {
LOGGER.trace(" SKIP: '{}'", elem.getName()); LOGGER.trace(" SKIP: '{}'", elem.getName());
continue; continue;
} }
@ -382,23 +399,40 @@ public class DataFactory {
continue; continue;
} }
alreadyAdded.add(dataName); alreadyAdded.add(dataName);
List<OptionSpecifyType> specificTypes = new ArrayList<>();
if (options != null) {
specificTypes = options.get(OptionSpecifyType.class);
}
Class<?> basicType = elem.getType();
if (basicType == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(elem.getName())) {
basicType = specify.clazz;
LOGGER.trace("Detect overwrite of typing ... '{}' => '{}'",
elem.getType().getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
}
LOGGER.trace(" + '{}'", elem.getName()); LOGGER.trace(" + '{}'", elem.getName());
if (DataAccess.isAddOnField(elem)) { if (DBAccessSQL.isAddOnField(elem)) {
final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem); final DataAccessAddOn addOn = DBAccessSQL.findAddOnforField(elem);
LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), LOGGER.trace("Create type for: {} ==> {} (ADD-ON)",
elem.getType()); AnnotationTools.getFieldName(elem, options).inTable(), basicType);
if (addOn != null) { if (addOn != null) {
addOn.createTables(tableName, primaryField, elem, tmpOut, preActionList, postActionList, addOn.createTables(tableName, primaryField, elem, tmpOut, preActionList, postActionList,
createIfNotExist, createDrop, fieldId); createIfNotExist, createDrop, fieldId, options);
} else { } else {
throw new DataAccessException("Element matked as add-on but add-on does not loaded: table:" throw new DataAccessException("Element matked as add-on but add-on does not loaded: table:"
+ tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + tableName + " field name=" + AnnotationTools.getFieldName(elem, options).inTable()
+ elem.getType()); + " type=" + basicType);
} }
} else { } else {
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem, options).inTable(),
basicType);
DataFactory.createTablesSpecificType(tableName, tablePrimaryKeyField, elem, tmpOut, preActionList, DataFactory.createTablesSpecificType(tableName, tablePrimaryKeyField, elem, tmpOut, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, elem.getType()); postActionList, createIfNotExist, createDrop, fieldId, basicType, options);
} }
fieldId++; fieldId++;
} }
@ -439,4 +473,4 @@ public class DataFactory {
return preActionList; return preActionList;
} }
} }

View File

@ -5,6 +5,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryAnd implements QueryItem { public class QueryAnd implements QueryItem {
protected final List<QueryItem> childs; protected final List<QueryItem> childs;
@ -41,14 +45,22 @@ public class QueryAnd implements QueryItem {
} }
@Override @Override
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) { for (final QueryItem elem : this.childs) {
elem.injectQuery(ps, iii); elem.injectQuery(ioDb, ps, iii);
} }
} }
public int size() { public int size() {
return this.childs.size(); return this.childs.size();
} }
@Override
public void generateFilter(final List<Bson> filters) {
final List<Bson> filtersLocal = new ArrayList<>();
for (final QueryItem elem : this.childs) {
elem.generateFilter(filtersLocal);
}
filters.add(Filters.and(filtersLocal.toArray(new Bson[0])));
}
} }

View File

@ -1,8 +1,16 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.client.model.Filters;
public class QueryCondition implements QueryItem { public class QueryCondition implements QueryItem {
static final Logger LOGGER = LoggerFactory.getLogger(DBAccess.class);
private final String key; private final String key;
private final String comparator; private final String comparator;
private final Object value; private final Object value;
@ -32,8 +40,28 @@ public class QueryCondition implements QueryItem {
} }
@Override @Override
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
DataAccess.addElement(ps, this.value, iii); ioDb.addElement(ps, this.value, iii);
iii.inc(); iii.inc();
} }
@Override
public void generateFilter(final List<Bson> filters) {
if ("=".equals(this.comparator)) {
filters.add(Filters.eq(this.key, this.value));
} else if ("!=".equals(this.comparator)) {
filters.add(Filters.ne(this.key, this.value));
} else if (">".equals(this.comparator)) {
filters.add(Filters.gt(this.key, this.value));
} else if (">=".equals(this.comparator)) {
filters.add(Filters.gte(this.key, this.value));
} else if ("<".equals(this.comparator)) {
filters.add(Filters.lt(this.key, this.value));
} else if ("<=".equals(this.comparator)) {
filters.add(Filters.lte(this.key, this.value));
} else {
LOGGER.error("Not manage comparison: '{}'", this.key);
}
}
} }

View File

@ -3,6 +3,10 @@ package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryInList<T> implements QueryItem { public class QueryInList<T> implements QueryItem {
protected final String key; protected final String key;
protected final String comparator; protected final String comparator;
@ -44,10 +48,15 @@ public class QueryInList<T> implements QueryItem {
} }
@Override @Override
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final Object elem : this.value) { for (final Object elem : this.value) {
DataAccess.addElement(ps, elem, iii); ioDb.addElement(ps, elem, iii);
iii.inc(); iii.inc();
} }
} }
@Override
public void generateFilter(final List<Bson> filters) {
filters.add(Filters.in(this.key, this.value));
}
} }

View File

@ -1,9 +1,17 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
public interface QueryItem { public interface QueryItem {
// For SQL mode query construction
void generateQuery(StringBuilder query, String tableName); void generateQuery(StringBuilder query, String tableName);
void injectQuery(PreparedStatement ps, CountInOut iii) throws Exception; // For SQL mode query injection
void injectQuery(DBAccessSQL ioDb, PreparedStatement ps, CountInOut iii) throws Exception;
// For No-SQL mode filter creation
void generateFilter(List<Bson> filters);
} }

View File

@ -1,6 +1,11 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryNotNull implements QueryItem { public class QueryNotNull implements QueryItem {
private final String key; private final String key;
@ -20,5 +25,11 @@ public class QueryNotNull implements QueryItem {
} }
@Override @Override
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {} public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii)
throws Exception {}
@Override
public void generateFilter(final List<Bson> filters) {
filters.add(Filters.exists(this.key));
}
} }

View File

@ -1,6 +1,11 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryNull implements QueryItem { public class QueryNull implements QueryItem {
private final String key; private final String key;
@ -20,5 +25,12 @@ public class QueryNull implements QueryItem {
} }
@Override @Override
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {} public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii)
throws Exception {}
@Override
public void generateFilter(final List<Bson> filters) {
// Not sure of the result ... maybe check it ...
filters.add(Filters.eq(this.key, null));
}
} }

View File

@ -1,8 +1,13 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryOr implements QueryItem { public class QueryOr implements QueryItem {
protected final List<QueryItem> childs; protected final List<QueryItem> childs;
@ -34,9 +39,18 @@ public class QueryOr implements QueryItem {
} }
@Override @Override
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) { for (final QueryItem elem : this.childs) {
elem.injectQuery(ps, iii); elem.injectQuery(ioDb, ps, iii);
} }
} }
@Override
public void generateFilter(final List<Bson> filters) {
final List<Bson> filtersLocal = new ArrayList<>();
for (final QueryItem elem : this.childs) {
elem.generateFilter(filtersLocal);
}
filters.add(Filters.or(filtersLocal.toArray(new Bson[0])));
}
} }

View File

@ -1,346 +0,0 @@
package org.kar.archidata.dataAccess.addOn;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
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.UUID;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.addOn.model.TableCoversLongLong;
import org.kar.archidata.dataAccess.addOn.model.TableCoversLongUUID;
import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDLong;
import org.kar.archidata.dataAccess.addOn.model.TableCoversUUIDUUID;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import jakarta.validation.constraints.NotNull;
public class AddOnDataJson implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnDataJson.class);
@Override
public Class<?> getAnnotationClass() {
return DataJson.class;
}
@Override
public String getSQLFieldType(final Field elem) throws DataAccessException {
final String fieldName = AnnotationTools.getFieldName(elem);
return DataFactory.convertTypeInSQL(String.class, fieldName);
}
@Override
public boolean isCompatibleField(final Field elem) {
final DataJson decorators = elem.getDeclaredAnnotation(DataJson.class);
return decorators != null;
}
@Override
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii)
throws IllegalArgumentException, IllegalAccessException, SQLException, JsonProcessingException {
final Object data = field.get(rootObject);
if (data == null) {
ps.setNull(iii.value, Types.VARCHAR);
}
final ObjectMapper objectMapper = new ObjectMapper();
final String dataString = objectMapper.writeValueAsString(data);
ps.setString(iii.value, dataString);
iii.inc();
}
@Override
public boolean canInsert(final Field field) {
return true;
}
@Override
public boolean isInsertAsync(final Field field) {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
return true;
}
@Override
public void generateQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
return;
}
@Override
public void fillFromQuery(
final ResultSet rs,
final Field field,
final Object data,
final CountInOut count,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final String jsonData = rs.getString(count.value);
count.inc();
if (!rs.wasNull()) {
final ObjectMapper objectMapper = new ObjectMapper();
if (field.getType() == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
if (listClass == Long.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Float.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Double.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Integer.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Short.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == String.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == UUID.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName());
}
final TypeFactory typeFactory = objectMapper.getTypeFactory();
final JavaType fieldType = typeFactory.constructType(field.getGenericType());
final Object dataParsed = objectMapper.readValue(jsonData, fieldType);
//final Object dataParsed = objectMapper.readValue(jsonData, field.getType());
field.set(data, dataParsed);
}
}
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId) throws Exception {
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class);
}
public static void addLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
/**
* Adds a remoteKey to the covers list of a data entry identified by the given class type and ID.
* If the covers list is null, it initializes it. If the remoteKey already exists in the list,
* the method returns without making any changes.
*
* @param clazz The class type to retrieve the table name from.
* @param id The ID of the data object to fetch.
* @param column The name of the column (currently not used, but may be used for specifying a field name).
* @param remoteKey The UUID to add to the covers list.
* @throws Exception If an error occurs during data retrieval or update.
*/
public static void addLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
// TODO: Get primary key name
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));// TODO: ,new OverrideFieldName("covers", column));
}
/**
* Adds a remoteKey to the covers list of a data entry identified by the given class type and ID.
* If the covers list is null, it initializes it. If the remoteKey already exists in the list,
* the method returns without making any changes.
*
* @param clazz The class type to retrieve the table name from.
* @param id The ID of the data object to fetch.
* @param column The name of the column (currently not used, but may be used for specifying a field name).
* @param remoteKey The UUID to add to the covers list.
* @throws Exception If an error occurs during data retrieval or update.
*/
public static void addLink(final Class<?> clazz, final UUID uuid, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void addLink(final Class<?> clazz, final UUID uuid, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID uuid, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<Long> newList = new ArrayList<>();
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID uuid, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<UUID> newList = new ArrayList<>();
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<Long> newList = new ArrayList<>();
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<UUID> newList = new ArrayList<>();
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
}

View File

@ -1,25 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import org.kar.archidata.model.UUIDGenericDataSoftDelete;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
public class LinkTableLongLong extends UUIDGenericDataSoftDelete {
public LinkTableLongLong() {
// nothing to do...
}
public LinkTableLongLong(final long object1Id, final long object2Id) {
this.object1Id = object1Id;
this.object2Id = object2Id;
}
@Schema(description = "Object reference 1")
@Column(nullable = false)
public Long object1Id;
@Schema(description = "Object reference 2")
@Column(nullable = false)
public Long object2Id;
}

View File

@ -1,27 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.UUID;
import org.kar.archidata.model.UUIDGenericDataSoftDelete;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
public class LinkTableLongUUID extends UUIDGenericDataSoftDelete {
public LinkTableLongUUID() {
// nothing to do...
}
public LinkTableLongUUID(final long object1Id, final UUID object2Id) {
this.object1Id = object1Id;
this.object2Id = object2Id;
}
@Schema(description = "Object reference 1")
@Column(nullable = false)
public Long object1Id;
@Schema(description = "Object reference 2")
@Column(nullable = false)
public UUID object2Id;
}

View File

@ -1,27 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.UUID;
import org.kar.archidata.model.UUIDGenericDataSoftDelete;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
public class LinkTableUUIDLong extends UUIDGenericDataSoftDelete {
public LinkTableUUIDLong() {
// nothing to do...
}
public LinkTableUUIDLong(final UUID object1Id, final long object2Id) {
this.object1Id = object1Id;
this.object2Id = object2Id;
}
@Schema(description = "Object reference 1")
@Column(nullable = false)
public UUID object1Id;
@Schema(description = "Object reference 2")
@Column(nullable = false)
public Long object2Id;
}

View File

@ -1,27 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.UUID;
import org.kar.archidata.model.UUIDGenericDataSoftDelete;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
public class LinkTableUUIDUUID extends UUIDGenericDataSoftDelete {
public LinkTableUUIDUUID() {
// nothing to do...
}
public LinkTableUUIDUUID(final UUID object1Id, final UUID object2Id) {
this.object1Id = object1Id;
this.object2Id = object2Id;
}
@Schema(description = "Object reference 1")
@Column(nullable = false)
public UUID object1Id;
@Schema(description = "Object reference 2")
@Column(nullable = false)
public UUID object2Id;
}

View File

@ -1,25 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class TableCoversLongLong {
public TableCoversLongLong() {
// nothing to do...
}
public TableCoversLongLong(final Long id, final List<Long> covers) {
this.id = id;
this.covers = covers;
}
@Id
public Long id;
@DataJson()
public List<Long> covers;
}

View File

@ -1,27 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class TableCoversLongUUID {
public TableCoversLongUUID() {
// nothing to do...
}
public TableCoversLongUUID(final Long id, final List<UUID> covers) {
this.id = id;
this.covers = new ArrayList<>(covers);
}
@Id
public Long id;
@DataJson()
public List<UUID> covers;
}

View File

@ -1,26 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class TableCoversUUIDLong {
public TableCoversUUIDLong() {
// nothing to do...
}
public TableCoversUUIDLong(final UUID uuid, final List<Long> covers) {
this.uuid = uuid;
this.covers = new ArrayList<>(covers);
}
@Id
public UUID uuid;
@DataJson()
public List<Long> covers;
}

View File

@ -1,25 +0,0 @@
package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class TableCoversUUIDUUID {
public TableCoversUUIDUUID() {
// nothing to do...
}
public TableCoversUUIDUUID(final UUID uuid, final List<UUID> covers) {
this.uuid = uuid;
this.covers = covers;
}
@Id
public UUID uuid;
@DataJson()
public List<UUID> covers;
}

View File

@ -0,0 +1,174 @@
package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field;
import java.util.List;
import org.bson.Document;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.validation.constraints.NotNull;
public class AddOnDataJson implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnDataJson.class);
@Override
public Class<?> getAnnotationClass() {
return DataJson.class;
}
@Override
public String getSQLFieldType(final Field elem, final QueryOptions options) throws DataAccessException {
final String fieldName = AnnotationTools.getFieldName(elem, options).inTable();
return DataFactory.convertTypeInSQL(String.class, fieldName);
}
@Override
public boolean isCompatibleField(final Field elem) {
final DataJson decorators = elem.getDeclaredAnnotation(DataJson.class);
return decorators != null;
}
@Override
public void insertData(
final DBAccessMorphia ioDb,
final Field field,
final Object rootObject,
final QueryOptions options,
final Document docSet,
final Document docUnSet) throws Exception {
/*
final Object data = field.get(rootObject);
if (data == null) {
ps.setNull(iii.value, Types.VARCHAR);
}
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
final String dataString = objectMapper.writeValueAsString(data);
ps.setString(iii.value, dataString);
iii.inc();
*/
}
@Override
public boolean canInsert(final Field field) {
return true;
}
@Override
public boolean isInsertAsync(final Field field) {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
return true;
}
@Override
public void generateQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
return;
}
@Override
public void fillFromDoc(
final DBAccessMorphia ioDb,
final Document doc,
final Field field,
final Object data,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
/*
final String fieldName = AnnotationTools.getFieldName(field);
if (!doc.containsKey(fieldName)) {
field.set(data, null);
return;
}
final String jsonData = rs.getString(count.value);
if (!rs.wasNull()) {
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
if (field.getType() == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
if (listClass == Long.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Float.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Double.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Integer.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == Short.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == String.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
if (listClass == UUID.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});// field.getType());
field.set(data, dataParsed);
return;
}
LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName());
}
final Object dataParsed = objectMapper.readValue(jsonData, field.getType());
field.set(data, dataParsed);
}
*/
}
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class, options);
}
}

View File

@ -1,36 +1,31 @@
package org.kar.archidata.dataAccess.addOn; package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.bson.Document;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter; import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryAnd; import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryInList;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.addOn.model.LinkTableLongLong; import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableGeneric;
import org.kar.archidata.dataAccess.addOn.model.LinkTableLongUUID;
import org.kar.archidata.dataAccess.addOn.model.LinkTableUUIDLong;
import org.kar.archidata.dataAccess.addOn.model.LinkTableUUIDUUID;
import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.OverrideTableName; import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToMany;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@ -44,11 +39,6 @@ public class AddOnManyToMany implements DataAccessAddOn {
return ManyToMany.class; return ManyToMany.class;
} }
@Override
public String getSQLFieldType(final Field elem) {
return null;
}
@Override @Override
public boolean isCompatibleField(final Field elem) { public boolean isCompatibleField(final Field elem) {
final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class); final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class);
@ -56,8 +46,13 @@ public class AddOnManyToMany implements DataAccessAddOn {
} }
@Override @Override
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) public void insertData(
throws SQLException, IllegalArgumentException, IllegalAccessException { final DBAccessMorphia ioDb,
final Field field,
final Object rootObject,
final QueryOptions options,
final Document docSet,
final Document docUnSet) throws Exception {
} }
@ -86,9 +81,12 @@ public class AddOnManyToMany implements DataAccessAddOn {
return false; return false;
} }
public static String generateLinkTableNameField(final String tableName, final Field field) throws Exception { public static String generateLinkTableNameField(
final String name = AnnotationTools.getFieldName(field); final String tableName,
return generateLinkTableName(tableName, name); final Field field,
final QueryOptions options) throws Exception {
final FieldName name = AnnotationTools.getFieldName(field, options);
return generateLinkTableName(tableName, name.inTable());
} }
public static String generateLinkTableName(final String tableName, final String name) { public static String generateLinkTableName(final String tableName, final String name) {
@ -120,8 +118,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
final String tmpVariable = "tmp_" + Integer.toString(count.value); final String tmpVariable = "tmp_" + Integer.toString(count.value);
querySelect.append(" (SELECT GROUP_CONCAT("); querySelect.append(" (SELECT GROUP_CONCAT(");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
final boolean mode = manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0; if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
if (mode) {
querySelect.append(".object2Id "); querySelect.append(".object2Id ");
} else { } else {
querySelect.append(".object1Id "); querySelect.append(".object1Id ");
@ -129,7 +126,6 @@ public class AddOnManyToMany implements DataAccessAddOn {
if ("sqlite".equals(ConfigBaseVariable.getDBType())) { if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(", "); querySelect.append(", ");
} else { } else {
querySelect.append("ORDER BY uuid ASC ");
querySelect.append("SEPARATOR "); querySelect.append("SEPARATOR ");
} }
querySelect.append("'"); querySelect.append("'");
@ -155,7 +151,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
querySelect.append(" = "); querySelect.append(" = ");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
querySelect.append("."); querySelect.append(".");
if (mode) { if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append("object1Id "); querySelect.append("object1Id ");
} else { } else {
querySelect.append("object2Id "); querySelect.append("object2Id ");
@ -163,7 +159,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(" GROUP BY "); querySelect.append(" GROUP BY ");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
if (mode) { if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append(".object1Id"); querySelect.append(".object1Id");
} else { } else {
querySelect.append(".object2Id"); querySelect.append(".object2Id");
@ -192,7 +188,6 @@ public class AddOnManyToMany implements DataAccessAddOn {
} }
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()) final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]; .getActualTypeArguments()[0];
// TODO: manage better the eager and lazy !!
if (objectClass == Long.class || objectClass == UUID.class) { if (objectClass == Long.class || objectClass == UUID.class) {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options); generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
} }
@ -201,35 +196,39 @@ public class AddOnManyToMany implements DataAccessAddOn {
return; return;
} }
if (objectClass == decorators.targetEntity()) { if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) { generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
throw new DataAccessException("EAGER is not supported for list of element...");
} else {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
}
} }
} }
@Override @Override
public void fillFromQuery( public void fillFromDoc(
final ResultSet rs, final DBAccessMorphia ioDb,
final Document doc,
final Field field, final Field field,
final Object data, final Object data,
final CountInOut count,
final QueryOptions options, final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception { final List<LazyGetter> lazyCall) throws Exception {
/*
if (field.getType() != List.class) { if (field.getType() != List.class) {
LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return; return;
} }
final String fieldName = AnnotationTools.getFieldName(field);
if (!doc.containsKey(fieldName)) {
field.set(data, null);
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()) final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]; .getActualTypeArguments()[0];
if (objectClass == Long.class) { if (objectClass == Long.class) {
final List<Long> idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); final List<Long> idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG);
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
return; return;
} else if (objectClass == UUID.class) { } else if (objectClass == UUID.class) {
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value); final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
return; return;
@ -240,10 +239,8 @@ public class AddOnManyToMany implements DataAccessAddOn {
} }
if (objectClass == decorators.targetEntity()) { if (objectClass == decorators.targetEntity()) {
final Class<?> foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType(); final Class<?> foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType();
if (decorators.fetch() == FetchType.EAGER) { if (foreignKeyType == Long.class) {
throw new DataAccessException("EAGER is not supported for list of element..."); final List<Long> idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG);
} else if (foreignKeyType == Long.class) {
final List<Long> idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG);
// field.set(data, idList); // field.set(data, idList);
count.inc(); count.inc();
if (idList != null && idList.size() > 0) { if (idList != null && idList.size() > 0) {
@ -253,7 +250,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
final List<Long> childs = new ArrayList<>(idList); final List<Long> childs = new ArrayList<>(idList);
// TODO: update to have get with abstract types .... // TODO: update to have get with abstract types ....
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField, childs))); new Condition(new QueryInList<>(idField, childs)));
if (foreignData == null) { if (foreignData == null) {
return; return;
@ -263,7 +260,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
lazyCall.add(lambda); lazyCall.add(lambda);
} }
} else if (foreignKeyType == UUID.class) { } else if (foreignKeyType == UUID.class) {
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value); final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
// field.set(data, idList); // field.set(data, idList);
count.inc(); count.inc();
if (idList != null && idList.size() > 0) { if (idList != null && idList.size() > 0) {
@ -273,7 +270,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
final List<UUID> childs = new ArrayList<>(idList); final List<UUID> childs = new ArrayList<>(idList);
// TODO: update to have get with abstract types .... // TODO: update to have get with abstract types ....
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField, childs))); new Condition(new QueryInList<>(idField, childs)));
if (foreignData == null) { if (foreignData == null) {
return; return;
@ -284,6 +281,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
} }
} }
} }
*/
} }
@Override @Override
@ -293,11 +291,13 @@ public class AddOnManyToMany implements DataAccessAddOn {
@Override @Override
public void asyncUpdate( public void asyncUpdate(
final DBAccessMorphia ioDb,
final String tableName, final String tableName,
final Object localKey, final Object localKey,
final Field field, final Field field,
final Object data, final Object data,
final List<LazyGetter> actions) throws Exception { final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
if (field.getType() != List.class) { if (field.getType() != List.class) {
LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return; return;
@ -308,38 +308,16 @@ public class AddOnManyToMany implements DataAccessAddOn {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<" throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
+ objectClass.getCanonicalName() + ">"); + objectClass.getCanonicalName() + ">");
} }
final String columnName = AnnotationTools.getFieldName(field); final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName); final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
if (localKey instanceof final Long localKeyLong) { actions.add(() -> {
if (objectClass == Long.class) { ioDb.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTableName),
actions.add(() -> { new Condition(new QueryCondition("object1Id", "=", localKey)),
DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), new OptionSpecifyType("object1Id", localKey.getClass()),
new Condition(new QueryCondition("object1Id", "=", localKeyLong))); new OptionSpecifyType("object2Id", objectClass));
}); });
asyncInsert(tableName, localKey, field, data, actions); asyncInsert(ioDb, tableName, localKey, field, data, actions, options);
} else {
actions.add(() -> {
DataAccess.deleteWhere(LinkTableLongUUID.class, new OverrideTableName(linkTableName),
new Condition(new QueryCondition("object1Id", "=", localKeyLong)));
});
asyncInsert(tableName, localKey, field, data, actions);
}
} else if (localKey instanceof final UUID localKeyUUID) {
if (objectClass == Long.class) {
actions.add(() -> {
DataAccess.deleteWhere(LinkTableUUIDLong.class, new OverrideTableName(linkTableName),
new Condition(new QueryCondition("object1Id", "=", localKeyUUID)));
});
asyncInsert(tableName, localKey, field, data, actions);
} else {
actions.add(() -> {
DataAccess.deleteWhere(LinkTableUUIDUUID.class, new OverrideTableName(linkTableName),
new Condition(new QueryCondition("object1Id", "=", localKeyUUID)));
});
asyncInsert(tableName, localKey, field, data, actions);
}
}
} }
@Override @Override
@ -349,11 +327,13 @@ public class AddOnManyToMany implements DataAccessAddOn {
@Override @Override
public void asyncInsert( public void asyncInsert(
final DBAccessMorphia ioDb,
final String tableName, final String tableName,
final Object localKey, final Object localKey,
final Field field, final Field field,
final Object data, final Object data,
final List<LazyGetter> actions) throws Exception { final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
if (data == null) { if (data == null) {
return; return;
} }
@ -367,155 +347,101 @@ public class AddOnManyToMany implements DataAccessAddOn {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<" throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
+ objectClass.getCanonicalName() + ">"); + objectClass.getCanonicalName() + ">");
} }
final String columnName = AnnotationTools.getFieldName(field); final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
@SuppressWarnings("unchecked")
final List<Object> dataCasted = (List<Object>) data;
if (dataCasted.size() == 0) {
return;
}
final List<LinkTableGeneric> insertElements = new ArrayList<>();
for (final Object remoteKey : dataCasted) {
if (remoteKey == null) {
throw new DataAccessException("Try to insert remote key with null value");
}
insertElements.add(new LinkTableGeneric(localKey, remoteKey));
}
if (insertElements.size() == 0) {
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted);
return;
}
actions.add(() -> {
ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName),
new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", objectClass));
});
}
@Override
public void drop(final DBAccessMorphia ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception {
final String columnName = AnnotationTools.getFieldName(field, options).inTable();
final String linkTableName = generateLinkTableName(tableName, columnName); final String linkTableName = generateLinkTableName(tableName, columnName);
if (localKey instanceof final Long localKeyLong) { final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
if (objectClass == Long.class) { .getActualTypeArguments()[0];
// ======================================================== ioDb.drop(LinkTableGeneric.class, new OverrideTableName(linkTableName),
// == Link a "Long" primary Key with List<Long> new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
// ======================================================== }
@SuppressWarnings("unchecked")
final List<Long> dataCasted = (List<Long>) data; @Override
if (dataCasted.size() == 0) { public void cleanAll(
return; final DBAccessMorphia ioDb,
} final String tableName,
final List<LinkTableLongLong> insertElements = new ArrayList<>(); final Field field,
for (final Long remoteKey : dataCasted) { final QueryOptions options) throws Exception {
if (remoteKey == null) { final String columnName = AnnotationTools.getFieldName(field, options).inTable();
throw new DataAccessException("Try to insert remote key with null value"); final String linkTableName = generateLinkTableName(tableName, columnName);
} final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
insertElements.add(new LinkTableLongLong(localKeyLong, remoteKey)); .getActualTypeArguments()[0];
} if (objectClass != Long.class && objectClass != UUID.class) {
if (insertElements.size() == 0) { throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + objectClass.getCanonicalName() + ">");
return; }
} ioDb.cleanAll(LinkTableGeneric.class, new OverrideTableName(linkTableName),
actions.add(() -> { new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); }
});
} else { public static void addLink(
// ======================================================== final DBAccess ioDb,
// == Link a "Long" primary Key with List<UUID> final Class<?> clazz,
// ======================================================== final long localKey,
@SuppressWarnings("unchecked") final String column,
final List<UUID> dataCasted = (List<UUID>) data; final long remoteKey) throws Exception {
if (dataCasted.size() == 0) { if (ioDb instanceof final DBAccessMorphia daSQL) {
return; final String tableName = AnnotationTools.getTableName(clazz);
} final String linkTableName = generateLinkTableName(tableName, column);
final List<LinkTableLongUUID> insertElements = new ArrayList<>(); /* final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; if (objectClass != Long.class && objectClass != UUID.class) { throw new
for (final UUID remoteKey : dataCasted) { * DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<" + objectClass.getCanonicalName() + ">"); } */
if (remoteKey == null) { final LinkTableGeneric insertElement = new LinkTableGeneric(localKey, remoteKey);
throw new DataAccessException("Try to insert remote key with null value"); daSQL.insert(insertElement, new OverrideTableName(linkTableName),
} new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
insertElements.add(new LinkTableLongUUID(localKeyLong, remoteKey)); } else if (ioDb instanceof final DBAccessMorphia dam) {
}
if (insertElements.size() == 0) {
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted);
return;
}
actions.add(() -> {
DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName));
});
}
} else if (localKey instanceof final UUID localKeyUUID) {
if (objectClass == Long.class) {
// ========================================================
// == Link a "UUID" primary Key with List<Long>
// ========================================================
@SuppressWarnings("unchecked")
final List<Long> dataCasted = (List<Long>) data;
if (dataCasted.size() == 0) {
return;
}
final List<LinkTableUUIDLong> insertElements = new ArrayList<>();
for (final Long remoteKey : dataCasted) {
if (remoteKey == null) {
throw new DataAccessException("Try to insert remote key with null value");
}
insertElements.add(new LinkTableUUIDLong(localKeyUUID, remoteKey));
}
if (insertElements.size() == 0) {
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted);
return;
}
actions.add(() -> {
DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName));
});
} else {
// ========================================================
// == Link a "UUID" primary Key with List<UUID>
// ========================================================
@SuppressWarnings("unchecked")
final List<UUID> dataCasted = (List<UUID>) data;
if (dataCasted.size() == 0) {
return;
}
final List<LinkTableUUIDUUID> insertElements = new ArrayList<>();
for (final UUID remoteKey : dataCasted) {
if (remoteKey == null) {
throw new DataAccessException("Try to insert remote key with null value");
}
insertElements.add(new LinkTableUUIDUUID(localKeyUUID, remoteKey));
}
if (insertElements.size() == 0) {
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted);
return;
}
actions.add(() -> {
DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName));
});
}
} else { } else {
throw new DataAccessException("Not manage access of remte key like ManyToMany other than Long or UUID: " throw new DataAccessException("DataAccess Not managed");
+ localKey.getClass().getCanonicalName());
} }
} }
@Override public static long removeLink(
public void drop(final String tableName, final Field field) throws Exception { final DBAccess ioDb,
final String columnName = AnnotationTools.getFieldName(field); final Class<?> clazz,
final String linkTableName = generateLinkTableName(tableName, columnName); final long localKey,
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()) final String column,
.getActualTypeArguments()[0]; final long remoteKey) throws Exception {
if (objectClass != Long.class && objectClass != UUID.class) { if (ioDb instanceof final DBAccessMorphia daSQL) {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<" final String tableName = AnnotationTools.getTableName(clazz);
+ objectClass.getCanonicalName() + ">"); final String linkTableName = generateLinkTableName(tableName, column);
return daSQL.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTableName),
new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey),
new QueryCondition("object2Id", "=", remoteKey))),
new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
} else if (ioDb instanceof final DBAccessMorphia dam) {
return 0L;
} else {
throw new DataAccessException("DataAccess Not managed");
} }
DataAccess.drop(LinkTableLongLong.class, new OverrideTableName(linkTableName));
}
@Override
public void cleanAll(final String tableName, final Field field) throws Exception {
final String columnName = AnnotationTools.getFieldName(field);
final String linkTableName = generateLinkTableName(tableName, columnName);
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass != Long.class && objectClass != UUID.class) {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
+ objectClass.getCanonicalName() + ">");
}
DataAccess.cleanAll(LinkTableLongLong.class, new OverrideTableName(linkTableName));
}
public static void addLink(final Class<?> clazz, final long localKey, final String column, final long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final String linkTableName = generateLinkTableName(tableName, column);
/* final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; if (objectClass != Long.class && objectClass != UUID.class) { throw new
* DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<" + objectClass.getCanonicalName() + ">"); } */
final LinkTableLongLong insertElement = new LinkTableLongLong(localKey, remoteKey);
DataAccess.insert(insertElement, new OverrideTableName(linkTableName));
}
public static int removeLink(final Class<?> clazz, final long localKey, final String column, final long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final String linkTableName = generateLinkTableName(tableName, column);
return DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName),
new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey),
new QueryCondition("object2Id", "=", remoteKey))));
} }
@Override @Override
@ -528,41 +454,22 @@ public class AddOnManyToMany implements DataAccessAddOn {
final List<String> postActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createIfNotExist,
final boolean createDrop, final boolean createDrop,
final int fieldId) throws Exception { final int fieldId,
final QueryOptions options) throws Exception {
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field); final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) { if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) {
// not the reference model to create base: // not the reference model to create base:
return; return;
} }
final String linkTableName = generateLinkTableNameField(tableName, field); final String linkTableName = generateLinkTableNameField(tableName, field, options);
final QueryOptions options = new QueryOptions(new OverrideTableName(linkTableName)); final QueryOptions options2 = new QueryOptions(new OverrideTableName(linkTableName));
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()) final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]; .getActualTypeArguments()[0];
if (objectClass != Long.class && objectClass != UUID.class) {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
+ objectClass.getCanonicalName() + ">");
}
final Class<?> primaryType = primaryField.getType(); final Class<?> primaryType = primaryField.getType();
if (primaryType == Long.class) { options2.add(new OptionSpecifyType("object1Id", primaryType));
if (objectClass == Long.class) { options2.add(new OptionSpecifyType("object2Id", objectClass));
final List<String> sqlCommand = DataFactory.createTable(LinkTableLongLong.class, options); final List<String> sqlCommand = DataFactory.createTable(LinkTableGeneric.class, options2);
postActionList.addAll(sqlCommand); postActionList.addAll(sqlCommand);
} else {
final List<String> sqlCommand = DataFactory.createTable(LinkTableLongUUID.class, options);
postActionList.addAll(sqlCommand);
}
} else if (primaryType == UUID.class) {
if (objectClass == Long.class) {
final List<String> sqlCommand = DataFactory.createTable(LinkTableUUIDLong.class, options);
postActionList.addAll(sqlCommand);
} else {
final List<String> sqlCommand = DataFactory.createTable(LinkTableUUIDUUID.class, options);
postActionList.addAll(sqlCommand);
}
} else {
throw new DataAccessException("Can not ManyToMany with other than primary key type Long or UUID Model: "
+ primaryType.getCanonicalName());
}
} }
} }

View File

@ -0,0 +1,233 @@
package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
import org.bson.Document;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.NotNull;
public class AddOnManyToOne implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
@Override
public Class<?> getAnnotationClass() {
return ManyToOne.class;
}
@Override
public String getSQLFieldType(final Field field, final QueryOptions options) throws Exception {
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
try {
return DataFactory.convertTypeInSQL(field.getType(), fieldName.inTable());
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public boolean isCompatibleField(final Field elem) {
return elem.getDeclaredAnnotation(ManyToOne.class) != null;
}
@Override
public void insertData(
final DBAccessMorphia ioDb,
final Field field,
final Object rootObject,
final QueryOptions options,
final Document docSet,
final Document docUnSet) throws Exception {
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
final Object data = field.get(rootObject);
if (field.get(data) == null) {
docUnSet.append(fieldName.inTable(), "");
return;
} else if (field.getType() == Long.class) {
final Long dataTyped = (Long) data;
docSet.append(fieldName.inTable(), dataTyped);
} else if (field.getType() == Integer.class) {
final Integer dataTyped = (Integer) data;
docSet.append(fieldName.inTable(), dataTyped);
} else if (field.getType() == Short.class) {
final Short dataTyped = (Short) data;
docSet.append(fieldName.inTable(), dataTyped);
} else if (field.getType() == String.class) {
final String dataTyped = (String) data;
docSet.append(fieldName.inTable(), dataTyped);
} else if (field.getType() == UUID.class) {
final UUID dataTyped = (UUID) data;
docSet.append(fieldName.inTable(), dataTyped);
} else {
final Field idField = AnnotationTools.getFieldOfId(field.getType());
final Object uid = idField.get(data);
if (uid == null) {
docUnSet.append(fieldName.inTable(), "");
} else {
docSet.append(fieldName.inTable(), uid);
}
}
}
@Override
public boolean canInsert(final Field field) {
if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class
|| field.getType() == String.class || field.getType() == UUID.class) {
return true;
}
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
if (field.getType() == decorators.targetEntity()) {
return true;
}
return false;
}
@Override
public boolean isInsertAsync(final Field field) throws Exception {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
final Class<?> classType = field.getType();
if (classType == Long.class || classType == Integer.class || classType == Short.class
|| classType == String.class || classType == UUID.class) {
return true;
}
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
if (field.getType() == decorators.targetEntity()) {
return true;
}
return false;
}
@Override
public void generateQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class
|| field.getType() == String.class || field.getType() == UUID.class) {
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
return;
}
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
if (field.getType() == decorators.targetEntity()) {
// no eager possible for no sql
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
}
}
@Override
public void fillFromDoc(
final DBAccessMorphia ioDb,
final Document doc,
final Field field,
final Object data,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
if (!doc.containsKey(fieldName.inTable())) {
field.set(data, null);
return;
}
// local field to manage no remote object to retrieve.
if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class
|| field.getType() == String.class || field.getType() == UUID.class) {
ioDb.setValueFromDoc(field.getType(), data, field, doc, lazyCall, options);
return;
}
final Class<?> objectClass = field.getType();
final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
final Field remotePrimaryKeyField = AnnotationTools.getFieldOfId(objectClass);
final Class<?> remotePrimaryKeyType = remotePrimaryKeyField.getType();
if (remotePrimaryKeyType == Long.class) {
// here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ...
final Long foreignKey = doc.getLong(fieldName);
if (foreignKey != null) {
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
// TODO: update to have get with abstract types ....
final Object foreignData = ioDb.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
} else if (remotePrimaryKeyType == UUID.class) {
// here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ...
final UUID foreignKey = doc.get(fieldName, UUID.class);
if (foreignKey != null) {
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
// TODO: update to have get with abstract types ....
final Object foreignData = ioDb.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
}
}
}
// TODO : refacto this table to manage a generic table with dynamic name to be serialisable with the default system
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
final Class<?> classType = field.getType();
if (classType == Long.class || classType == Integer.class || classType == Short.class
|| classType == String.class || classType == UUID.class) {
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, classType, options);
} else {
LOGGER.error("Support only the Long remote field of ecternal primary keys...");
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, Long.class, options);
}
}
}

View File

@ -0,0 +1,312 @@
package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bson.Document;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToMany;
import jakarta.validation.constraints.NotNull;
public class AddOnOneToMany implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnOneToMany.class);
static final String SEPARATOR_LONG = "-";
/** 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<Long> ids) {
final List<Long> 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<Long> getListOfIds(final ResultSet rs, final int iii) throws SQLException {
final String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
final List<Long> 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 OneToMany.class;
}
@Override
public boolean isCompatibleField(final Field field) {
final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class);
return decorators != null;
}
@Override
public void insertData(
final DBAccessMorphia ioDb,
final Field field,
final Object rootObject,
final QueryOptions options,
final Document docSet,
final Document docUnSet) throws Exception {
throw new IllegalAccessException("Can not generate an inset of @OneToMany");
}
@Override
public boolean canInsert(final Field field) {
return false;
}
@Override
public boolean isInsertAsync(final Field field) throws Exception {
// TODO: can be implemented later...
return false;
}
@Override
public boolean canRetrieve(final Field field) {
if (field.getType() != List.class) {
return false;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass == Long.class || objectClass == UUID.class) {
return true;
}
final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class);
if (decorators == null) {
return false;
}
if (decorators.targetEntity() == objectClass) {
return true;
}
return false;
}
public void generateConcatQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options,
final Class<?> targetEntity,
final String mappedBy) throws Exception {
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
final String remoteTableName = AnnotationTools.getTableName(targetEntity);
final FieldName remoteTablePrimaryKeyName = AnnotationTools
.getFieldName(AnnotationTools.getPrimaryKeyField(targetEntity), options);
final String tmpRemoteVariable = "tmp_" + Integer.toString(count.value);
final String remoteDeletedFieldName = AnnotationTools.getDeletedFieldName(targetEntity);
querySelect.append(" (SELECT GROUP_CONCAT(");
querySelect.append(tmpRemoteVariable);
querySelect.append(".");
querySelect.append(remoteTablePrimaryKeyName.inTable());
querySelect.append(" ");
if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(", ");
} else {
querySelect.append("SEPARATOR ");
}
querySelect.append("'");
if (objectClass == Long.class) {
querySelect.append(SEPARATOR_LONG);
}
querySelect.append("') FROM ");
querySelect.append(remoteTableName);
querySelect.append(" ");
querySelect.append(tmpRemoteVariable);
querySelect.append(" WHERE ");
if (remoteDeletedFieldName != null) {
querySelect.append(tmpRemoteVariable);
querySelect.append(".");
querySelect.append(remoteDeletedFieldName);
querySelect.append(" = false");
querySelect.append(" AND ");
}
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(primaryKey);
querySelect.append(" = ");
querySelect.append(tmpRemoteVariable);
querySelect.append(".");
querySelect.append(mappedBy);
querySelect.append(" ");
querySelect.append(") AS ");
querySelect.append(name);
querySelect.append(" ");
}
@Override
public void generateQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
if (field.getType() != List.class) {
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class);
if (decorators == null) {
return;
}
// TODO: manage better the eager and lazy !!
if (objectClass == Long.class || objectClass == UUID.class) {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options,
decorators.targetEntity(), decorators.mappedBy());
return;
}
if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
throw new DataAccessException("EAGER is not supported for list of element...");
} else {
// Force a copy of the primaryKey to permit the async retrieve of the data
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(primaryKey);
querySelect.append(" AS tmp_");
querySelect.append(Integer.toString(count.value));
}
}
}
@Override
public void fillFromDoc(
final DBAccessMorphia ioDb,
final Document doc,
final Field field,
final Object data,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
if (field.getType() != List.class) {
LOGGER.error("Can not OneToMany with other than List Model: {}", field.getType().getCanonicalName());
return;
}
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
if (!doc.containsKey(fieldName)) {
field.set(data, null);
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class);
if (decorators == null) {
return;
}
if (objectClass == Long.class || objectClass == UUID.class) {
final Object value = doc.get(fieldName, field.getType());
field.set(data, value);
return;
}
if (objectClass == decorators.targetEntity()) {
Long parentIdTmp = null;
UUID parendUuidTmp = null;
try {
final Object value = doc.get(fieldName);
if (value instanceof final Long valueCasted) {
parentIdTmp = valueCasted;
} else if (value instanceof final UUID valueCasted) {
parendUuidTmp = valueCasted;
}
} catch (final Exception ex) {
LOGGER.error("fail to find the correct type... {}", ex.getMessage());
}
final Long parentId = parentIdTmp;
final UUID parendUuid = parendUuidTmp;
final String mappingKey = decorators.mappedBy();
// We get the parent ID ... ==> need to request the list of elements
if (objectClass == Long.class) {
LOGGER.error("Need to retreive all primary key of all elements");
//field.set(data, idList);
return;
} else if (objectClass == UUID.class) {
LOGGER.error("Need to retreive all primary key of all elements");
//field.set(data, idList);
return;
}
if (objectClass == decorators.targetEntity()) {
if (parentId != null) {
final LazyGetter lambda = () -> {
@SuppressWarnings("unchecked")
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(mappingKey, "=", parentId)));
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
} else if (parendUuid != null) {
final LazyGetter lambda = () -> {
@SuppressWarnings("unchecked")
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(mappingKey, "=", parendUuid)));
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
}
}
}
// TODO : refacto this table to manage a generic table with dynamic name to be serialize with the default system
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
// This is a remote field ==> nothing to generate (it is stored in the remote object
}
}

View File

@ -1,11 +1,15 @@
package org.kar.archidata.dataAccess; package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.bson.Document;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
public interface DataAccessAddOn { public interface DataAccessAddOn {
@ -16,7 +20,9 @@ public interface DataAccessAddOn {
/** Get the SQL type that is needed to declare for the specific Field Type. /** Get the SQL type that is needed to declare for the specific Field Type.
* @param elem Field to declare. * @param elem Field to declare.
* @return SQL type to create. */ * @return SQL type to create. */
String getSQLFieldType(Field elem) throws Exception; default String getSQLFieldType(final Field elem, final QueryOptions options) throws Exception {
return null;
}
/** Check if the field is manage by the local add-on /** Check if the field is manage by the local add-on
* @param elem Field to inspect. * @param elem Field to inspect.
@ -29,8 +35,13 @@ public interface DataAccessAddOn {
* @param iii The index of injection * @param iii The index of injection
* @return the new index of injection in case of multiple value management * @return the new index of injection in case of multiple value management
* @throws SQLException */ * @throws SQLException */
void insertData(PreparedStatement ps, final Field field, Object data, CountInOut iii) void insertData(
throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; final DBAccessMorphia ioDb,
final Field field,
final Object rootObject,
final QueryOptions options,
final Document docSet,
final Document docUnSet) throws Exception;
/** Element can insert in the single request /** Element can insert in the single request
* @param field * @param field
@ -57,11 +68,11 @@ public interface DataAccessAddOn {
QueryOptions options) throws Exception; QueryOptions options) throws Exception;
// Return the number of colomn read // Return the number of colomn read
void fillFromQuery( void fillFromDoc(
ResultSet rs, final DBAccessMorphia ioDb,
Document doc,
Field field, Field field,
Object data, Object data,
CountInOut count,
QueryOptions options, QueryOptions options,
final List<LazyGetter> lazyCall) final List<LazyGetter> lazyCall)
throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
@ -84,7 +95,8 @@ public interface DataAccessAddOn {
List<String> postActionList, List<String> postActionList,
boolean createIfNotExist, boolean createIfNotExist,
boolean createDrop, boolean createDrop,
int fieldId) throws Exception; int fieldId,
final QueryOptions options) throws Exception;
/** Some action must be done asynchronously for update or remove element /** Some action must be done asynchronously for update or remove element
* @param field * @param field
@ -100,11 +112,13 @@ public interface DataAccessAddOn {
* @param data Data that might be inserted. * @param data Data that might be inserted.
* @param actions Asynchronous action to do after main request. */ * @param actions Asynchronous action to do after main request. */
default void asyncInsert( default void asyncInsert(
final DBAccessMorphia ioDb,
final String tableName, final String tableName,
final Object localId, final Object localId,
final Field field, final Field field,
final Object data, final Object data,
final List<LazyGetter> actions) throws Exception { final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
} }
@ -122,19 +136,26 @@ public interface DataAccessAddOn {
* @param data Data that might be inserted. * @param data Data that might be inserted.
* @param actions Asynchronous action to do after main request. */ * @param actions Asynchronous action to do after main request. */
default void asyncUpdate( default void asyncUpdate(
final DBAccessMorphia ioDb,
final String tableName, final String tableName,
final Object localId, final Object localId,
final Field field, final Field field,
final Object data, final Object data,
final List<LazyGetter> actions) throws Exception { final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
} }
default void drop(final String tableName, final Field field) throws Exception { default void drop(final DBAccessMorphia ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception {
} }
default void cleanAll(final String tableName, final Field field) throws Exception { default void cleanAll(
final DBAccessMorphia ioDb,
final String tableName,
final Field field,
final QueryOptions options) throws Exception {
} }

View File

@ -0,0 +1,287 @@
package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
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.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.addOnSQL.model.TableCoversGeneric;
import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import jakarta.validation.constraints.NotNull;
public class AddOnDataJson implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnDataJson.class);
@Override
public Class<?> getAnnotationClass() {
return DataJson.class;
}
@Override
public String getSQLFieldType(final Field elem, final QueryOptions options) throws DataAccessException {
final FieldName fieldName = AnnotationTools.getFieldName(elem, options);
return DataFactory.convertTypeInSQL(String.class, fieldName.inTable());
}
@Override
public boolean isCompatibleField(final Field elem) {
final DataJson decorators = elem.getDeclaredAnnotation(DataJson.class);
return decorators != null;
}
@Override
public void insertData(
final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii)
throws IllegalArgumentException, IllegalAccessException, SQLException, JsonProcessingException {
final Object data = field.get(rootObject);
if (data == null) {
ps.setNull(iii.value, Types.VARCHAR);
}
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
final String dataString = objectMapper.writeValueAsString(data);
ps.setString(iii.value, dataString);
iii.inc();
}
@Override
public boolean canInsert(final Field field) {
return true;
}
@Override
public boolean isInsertAsync(final Field field) {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
return true;
}
@Override
public void generateQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
querySelect.append(" ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(name);
count.inc();
return;
}
@Override
public void fillFromQuery(
final DBAccessSQL ioDb,
final ResultSet rs,
final Field field,
final Object data,
final CountInOut count,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
final String jsonData = rs.getString(count.value);
count.inc();
if (!rs.wasNull()) {
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
if (field.getType() == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
if (listClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(field.getName())) {
listClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing var={} ... '{}' => '{}'", field.getName(),
listClass.getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
}
if (listClass == Long.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Float.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Double.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Integer.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Short.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == String.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == UUID.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == ObjectId.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<ObjectId>>() {});
field.set(data, dataParsed);
return;
}
LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName());
}
final TypeFactory typeFactory = objectMapper.getTypeFactory();
Class<?> listClass = field.getType();
if (listClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(field.getName())) {
listClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing var={} ... '{}' => '{}'", field.getName(),
listClass.getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
final JavaType javaType = typeFactory.constructType(listClass);
final Object dataParsed = objectMapper.readValue(jsonData, javaType);
field.set(data, dataParsed);
} else {
final JavaType fieldType = typeFactory.constructType(field.getGenericType());
final Object dataParsed = objectMapper.readValue(jsonData, fieldType);
field.set(data, dataParsed);
}
}
}
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class, options);
}
public static void addLink(
final DBAccess ioDb,
final Class<?> clazz,
final String columnId,
final Object id,
final String columnList,
final Object remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("id", id.getClass()),
new OptionSpecifyType("covers", remoteKey.getClass(), true));
if (columnId != null && !columnId.equals("id")) {
options.add(new OptionRenameColumn("id", columnId));
}
if (columnList != null && !columnList.equals("covers")) {
options.add(new OptionRenameColumn("covers", columnList));
}
final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, id, options.getAllArray());
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final Object elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
ioDb.update(data, data.id, List.of("covers"), options.getAllArray());
}
public static void removeLink(
final DBAccess ioDb,
final Class<?> clazz,
final String columnId,
final Object id,
final String columnList,
final Object remoteKey) throws Exception {
if (ioDb instanceof final DBAccessSQL daSQL) {
final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("id", id.getClass()),
new OptionSpecifyType("covers", remoteKey.getClass(), true));
if (columnId != null && !columnId.equals("id")) {
options.add(new OptionRenameColumn("id", columnId));
}
if (columnList != null && !columnList.equals("covers")) {
options.add(new OptionRenameColumn("covers", columnList));
}
final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, id, options.getAllArray());
if (data.covers == null) {
return;
}
final List<Object> newList = new ArrayList<>();
for (final Object elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
ioDb.update(data, data.id, List.of("covers"), options.getAllArray());
} else if (ioDb instanceof final DBAccessMorphia dam) {
} else {
throw new DataAccessException("DataAccess Not managed");
}
}
}

View File

@ -0,0 +1,465 @@
package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryInList;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.addOnSQL.model.LinkTableGeneric;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.validation.constraints.NotNull;
public class AddOnManyToMany implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class);
static final String SEPARATOR_LONG = "-";
static final String SEPARATOR_UUID = "_";
@Override
public Class<?> getAnnotationClass() {
return ManyToMany.class;
}
@Override
public boolean isCompatibleField(final Field elem) {
final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class);
return decorators != null;
}
@Override
public void insertData(
final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
}
@Override
public boolean canInsert(final Field field) {
return false;
}
@Override
public boolean canRetrieve(final Field field) {
if (field.getType() != List.class) {
return false;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass == Long.class || objectClass == UUID.class) {
return true;
}
final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class);
if (decorators == null) {
return false;
}
if (decorators.targetEntity() == objectClass) {
return true;
}
return false;
}
public static String generateLinkTableNameField(
final String tableName,
final Field field,
final QueryOptions options) throws Exception {
final FieldName name = AnnotationTools.getFieldName(field, options);
return generateLinkTableName(tableName, name.inTable());
}
public static String generateLinkTableName(final String tableName, final String name) {
String localName = name;
if (name.endsWith("s")) {
localName = name.substring(0, name.length() - 1);
}
return tableName + "_link_" + localName;
}
public void generateConcatQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
String linkTableName = generateLinkTableName(tableName, name);
if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) {
// TODO: get the remote table name .....
final String remoteTableName = AnnotationTools.getTableName(manyToMany.targetEntity());
linkTableName = generateLinkTableName(remoteTableName, manyToMany.mappedBy());
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
final String tmpVariable = "tmp_" + Integer.toString(count.value);
querySelect.append(" (SELECT GROUP_CONCAT(");
querySelect.append(tmpVariable);
if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append(".object2Id ");
} else {
querySelect.append(".object1Id ");
}
if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(", ");
} else {
querySelect.append("SEPARATOR ");
}
querySelect.append("'");
if (objectClass == Long.class) {
querySelect.append(SEPARATOR_LONG);
} else if (objectClass == UUID.class) {} else {
final Class<?> foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType();
if (foreignKeyType == Long.class) {
querySelect.append(SEPARATOR_LONG);
}
}
querySelect.append("') FROM ");
querySelect.append(linkTableName);
querySelect.append(" ");
querySelect.append(tmpVariable);
querySelect.append(" WHERE ");
querySelect.append(tmpVariable);
querySelect.append(".deleted = false");
querySelect.append(" AND ");
querySelect.append(tableName);
querySelect.append(".");
querySelect.append(primaryKey);
querySelect.append(" = ");
querySelect.append(tmpVariable);
querySelect.append(".");
if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append("object1Id ");
} else {
querySelect.append("object2Id ");
}
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(" GROUP BY ");
querySelect.append(tmpVariable);
if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append(".object1Id");
} else {
querySelect.append(".object2Id");
}
}
querySelect.append(") AS ");
querySelect.append(name);
querySelect.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" + */
count.inc();
}
@Override
public void generateQuery(
@NotNull final String tableName,
@NotNull final String primaryKey,
@NotNull final Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull final String name,
@NotNull final CountInOut count,
final QueryOptions options) throws Exception {
if (field.getType() != List.class) {
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
// TODO: manage better the eager and lazy !!
if (objectClass == Long.class || objectClass == UUID.class) {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
}
final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
throw new DataAccessException("EAGER is not supported for list of element...");
} else {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
}
}
}
@Override
public void fillFromQuery(
final DBAccessSQL ioDb,
final ResultSet rs,
final Field field,
final Object data,
final CountInOut count,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
if (field.getType() != List.class) {
LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass == Long.class) {
final List<Long> idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG);
field.set(data, idList);
count.inc();
return;
} else if (objectClass == UUID.class) {
final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
field.set(data, idList);
count.inc();
return;
}
final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
final Class<?> foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType();
if (decorators.fetch() == FetchType.EAGER) {
throw new DataAccessException("EAGER is not supported for list of element...");
} else if (foreignKeyType == Long.class) {
final List<Long> idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG);
// field.set(data, idList);
count.inc();
if (idList != null && idList.size() > 0) {
final FieldName idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass),
options);
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
final List<Long> childs = new ArrayList<>(idList);
// TODO: update to have get with abstract types ....
@SuppressWarnings("unchecked")
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField.inTable(), childs)));
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
} else if (foreignKeyType == UUID.class) {
final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
// field.set(data, idList);
count.inc();
if (idList != null && idList.size() > 0) {
final FieldName idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass),
options);
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
final List<UUID> childs = new ArrayList<>(idList);
// TODO: update to have get with abstract types ....
@SuppressWarnings("unchecked")
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField.inTable(), childs)));
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
}
}
}
@Override
public boolean isUpdateAsync(final Field field) {
return true;
}
@Override
public void asyncUpdate(
final DBAccessSQL ioDb,
final String tableName,
final Object localKey,
final Field field,
final Object data,
final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
if (field.getType() != List.class) {
LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass != Long.class && objectClass != UUID.class) {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
+ objectClass.getCanonicalName() + ">");
}
final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
actions.add(() -> {
ioDb.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTableName),
new Condition(new QueryCondition("object1Id", "=", localKey)),
new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", objectClass));
});
asyncInsert(ioDb, tableName, localKey, field, data, actions, options);
}
@Override
public boolean isInsertAsync(final Field field) {
return true;
}
@Override
public void asyncInsert(
final DBAccessSQL ioDb,
final String tableName,
final Object localKey,
final Field field,
final Object data,
final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
if (data == null) {
return;
}
if (field.getType() != List.class) {
LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return;
}
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (objectClass != Long.class && objectClass != UUID.class) {
throw new DataAccessException("Can not ManyToMany with other than List<Long> or List<UUID> Model: List<"
+ objectClass.getCanonicalName() + ">");
}
final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
@SuppressWarnings("unchecked")
final List<Long> dataCasted = (List<Long>) data;
if (dataCasted.size() == 0) {
return;
}
final List<LinkTableGeneric> insertElements = new ArrayList<>();
for (final Long remoteKey : dataCasted) {
if (remoteKey == null) {
throw new DataAccessException("Try to insert remote key with null value");
}
insertElements.add(new LinkTableGeneric(localKey, remoteKey));
}
if (insertElements.size() == 0) {
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted);
return;
}
actions.add(() -> {
ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName),
new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", objectClass));
});
}
@Override
public void drop(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception {
final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
ioDb.drop(LinkTableGeneric.class, new OverrideTableName(linkTableName));
}
@Override
public void cleanAll(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception {
final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
ioDb.cleanAll(LinkTableGeneric.class, new OverrideTableName(linkTableName));
}
public static void addLink(
final DBAccess ioDb,
final Class<?> clazz,
final Object localKey,
final String column,
final Object remoteKey) throws Exception {
if (ioDb instanceof final DBAccessSQL daSQL) {
final String tableName = AnnotationTools.getTableName(clazz);
final String linkTableName = generateLinkTableName(tableName, column);
final LinkTableGeneric insertElement = new LinkTableGeneric(localKey, remoteKey);
daSQL.insert(insertElement, new OverrideTableName(linkTableName),
new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", remoteKey.getClass()));
} else if (ioDb instanceof final DBAccessMorphia dam) {
} else {
throw new DataAccessException("DataAccess Not managed");
}
}
public static long removeLink(
final DBAccess ioDb,
final Class<?> clazz,
final Object localKey,
final String column,
final Object remoteKey) throws Exception {
if (ioDb instanceof final DBAccessSQL daSQL) {
final String tableName = AnnotationTools.getTableName(clazz);
final String linkTableName = generateLinkTableName(tableName, column);
return daSQL.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTableName),
new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey),
new QueryCondition("object2Id", "=", remoteKey))),
new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", remoteKey.getClass()));
} else if (ioDb instanceof final DBAccessMorphia dam) {
return 0L;
} else {
throw new DataAccessException("DataAccess Not managed");
}
}
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) {
// not the reference model to create base:
return;
}
final String linkTableName = generateLinkTableNameField(tableName, field, options);
final QueryOptions options2 = new QueryOptions(new OverrideTableName(linkTableName));
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
final Class<?> primaryType = primaryField.getType();
options2.add(new OptionSpecifyType("object1Id", primaryType));
options2.add(new OptionSpecifyType("object2Id", objectClass));
final List<String> sqlCommand = DataFactory.createTable(LinkTableGeneric.class, options2);
postActionList.addAll(sqlCommand);
}
}

View File

@ -1,4 +1,4 @@
package org.kar.archidata.dataAccess.addOn; package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -8,9 +8,9 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter; import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
@ -32,10 +32,10 @@ public class AddOnManyToOne implements DataAccessAddOn {
} }
@Override @Override
public String getSQLFieldType(final Field field) throws Exception { public String getSQLFieldType(final Field field, final QueryOptions options) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field); final FieldName fieldName = AnnotationTools.getFieldName(field, options);
try { try {
return DataFactory.convertTypeInSQL(field.getType(), fieldName); return DataFactory.convertTypeInSQL(field.getType(), fieldName.inTable());
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -48,8 +48,12 @@ public class AddOnManyToOne implements DataAccessAddOn {
} }
@Override @Override
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) public void insertData(
throws Exception { final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii) throws Exception {
final Object data = field.get(rootObject); final Object data = field.get(rootObject);
if (data == null) { if (data == null) {
if (field.getType() == Long.class) { if (field.getType() == Long.class) {
@ -149,7 +153,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
if (field.getType() == decorators.targetEntity()) { if (field.getType() == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) { if (decorators.fetch() == FetchType.EAGER) {
// TODO: rework this to have a lazy mode ... // TODO: rework this to have a lazy mode ...
DataAccess.generateSelectField(querySelect, query, field.getType(), options, count); DBAccessSQL.generateSelectField(querySelect, query, field.getType(), options, count);
final Class<?> subType = field.getType(); final Class<?> subType = field.getType();
final String subTableName = AnnotationTools.getTableName(subType); final String subTableName = AnnotationTools.getTableName(subType);
final Field idField = AnnotationTools.getFieldOfId(subType); final Field idField = AnnotationTools.getFieldOfId(subType);
@ -158,11 +162,11 @@ public class AddOnManyToOne implements DataAccessAddOn {
query.append("` ON "); query.append("` ON ");
query.append(subTableName); query.append(subTableName);
query.append("."); query.append(".");
query.append(AnnotationTools.getFieldName(idField)); query.append(AnnotationTools.getFieldName(idField, options).inTable());
query.append(" = "); query.append(" = ");
query.append(tableName); query.append(tableName);
query.append("."); query.append(".");
query.append(AnnotationTools.getFieldName(field)); query.append(AnnotationTools.getFieldName(field, options).inTable());
} else { } else {
querySelect.append(" "); querySelect.append(" ");
querySelect.append(tableName); querySelect.append(tableName);
@ -178,6 +182,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
@Override @Override
public void fillFromQuery( public void fillFromQuery(
final DBAccessSQL ioDb,
final ResultSet rs, final ResultSet rs,
final Field field, final Field field,
final Object data, final Object data,
@ -233,8 +238,8 @@ public class AddOnManyToOne implements DataAccessAddOn {
if (objectClass == decorators.targetEntity()) { if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) { if (decorators.fetch() == FetchType.EAGER) {
final CountInOut countNotNull = new CountInOut(0); final CountInOut countNotNull = new CountInOut(0);
final Object dataNew = DataAccess.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, final Object dataNew = ioDb.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, options,
options, lazyCall); lazyCall);
if (dataNew != null && countNotNull.value != 0) { if (dataNew != null && countNotNull.value != 0) {
field.set(data, dataNew); field.set(data, dataNew);
} }
@ -250,7 +255,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
// In the lazy mode, the request is done in asynchronous mode, they will be done after... // In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> { final LazyGetter lambda = () -> {
// TODO: update to have get with abstract types .... // TODO: update to have get with abstract types ....
final Object foreignData = DataAccess.get(decorators.targetEntity(), foreignKey); final Object foreignData = ioDb.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) { if (foreignData == null) {
return; return;
} }
@ -260,13 +265,13 @@ public class AddOnManyToOne implements DataAccessAddOn {
} }
} else if (remotePrimaryKeyType == UUID.class) { } else if (remotePrimaryKeyType == UUID.class) {
// here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ... // here we have the field, the data and the the remote value ==> can create callback that generate the update of the value ...
final UUID foreignKey = DataAccess.getListOfRawUUID(rs, count.value); final UUID foreignKey = ioDb.getListOfRawUUID(rs, count.value);
count.inc(); count.inc();
if (foreignKey != null) { if (foreignKey != null) {
// In the lazy mode, the request is done in asynchronous mode, they will be done after... // In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> { final LazyGetter lambda = () -> {
// TODO: update to have get with abstract types .... // TODO: update to have get with abstract types ....
final Object foreignData = DataAccess.get(decorators.targetEntity(), foreignKey); final Object foreignData = ioDb.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) { if (foreignData == null) {
return; return;
} }
@ -289,16 +294,17 @@ public class AddOnManyToOne implements DataAccessAddOn {
final List<String> postActionList, final List<String> postActionList,
final boolean createIfNotExist, final boolean createIfNotExist,
final boolean createDrop, final boolean createDrop,
final int fieldId) throws Exception { final int fieldId,
final QueryOptions options) throws Exception {
final Class<?> classType = field.getType(); final Class<?> classType = field.getType();
if (classType == Long.class || classType == Integer.class || classType == Short.class if (classType == Long.class || classType == Integer.class || classType == Short.class
|| classType == String.class || classType == UUID.class) { || classType == String.class || classType == UUID.class) {
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, classType); postActionList, createIfNotExist, createDrop, fieldId, classType, options);
} else { } else {
LOGGER.error("Support only the Long remote field of ecternal primary keys..."); LOGGER.error("Support only the Long remote field of ecternal primary keys...");
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, Long.class); postActionList, createIfNotExist, createDrop, fieldId, Long.class, options);
} }
} }
} }

View File

@ -1,4 +1,4 @@
package org.kar.archidata.dataAccess.addOn; package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
@ -11,9 +11,9 @@ import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataAccessAddOn;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.LazyGetter; import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryCondition;
@ -65,10 +65,10 @@ public class AddOnOneToMany implements DataAccessAddOn {
} }
@Override @Override
public String getSQLFieldType(final Field field) throws Exception { public String getSQLFieldType(final Field field, final QueryOptions options) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field); final FieldName fieldName = AnnotationTools.getFieldName(field, options);
try { try {
return DataFactory.convertTypeInSQL(Long.class, fieldName); return DataFactory.convertTypeInSQL(Long.class, fieldName.inTable());
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -83,8 +83,12 @@ public class AddOnOneToMany implements DataAccessAddOn {
} }
@Override @Override
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) public void insertData(
throws SQLException, IllegalArgumentException, IllegalAccessException { final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
throw new IllegalAccessException("Can not generate an inset of @OneToMany"); throw new IllegalAccessException("Can not generate an inset of @OneToMany");
} }
@ -133,15 +137,15 @@ public class AddOnOneToMany implements DataAccessAddOn {
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()) final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]; .getActualTypeArguments()[0];
final String remoteTableName = AnnotationTools.getTableName(targetEntity); final String remoteTableName = AnnotationTools.getTableName(targetEntity);
final String remoteTablePrimaryKeyName = AnnotationTools final FieldName remoteTablePrimaryKeyName = AnnotationTools
.getFieldName(AnnotationTools.getPrimaryKeyField(targetEntity)); .getFieldName(AnnotationTools.getPrimaryKeyField(targetEntity), options);
final String tmpRemoteVariable = "tmp_" + Integer.toString(count.value); final String tmpRemoteVariable = "tmp_" + Integer.toString(count.value);
final String remoteDeletedFieldName = AnnotationTools.getDeletedFieldName(targetEntity); final String remoteDeletedFieldName = AnnotationTools.getDeletedFieldName(targetEntity);
querySelect.append(" (SELECT GROUP_CONCAT("); querySelect.append(" (SELECT GROUP_CONCAT(");
querySelect.append(tmpRemoteVariable); querySelect.append(tmpRemoteVariable);
querySelect.append("."); querySelect.append(".");
querySelect.append(remoteTablePrimaryKeyName); querySelect.append(remoteTablePrimaryKeyName.inTable());
querySelect.append(" "); querySelect.append(" ");
if ("sqlite".equals(ConfigBaseVariable.getDBType())) { if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(", "); querySelect.append(", ");
@ -219,6 +223,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
@Override @Override
public void fillFromQuery( public void fillFromQuery(
final DBAccessSQL ioDb,
final ResultSet rs, final ResultSet rs,
final Field field, final Field field,
final Object data, final Object data,
@ -236,12 +241,12 @@ public class AddOnOneToMany implements DataAccessAddOn {
return; return;
} }
if (objectClass == Long.class) { if (objectClass == Long.class) {
final List<Long> idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); final List<Long> idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG);
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
return; return;
} else if (objectClass == UUID.class) { } else if (objectClass == UUID.class) {
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value); final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
return; return;
@ -255,7 +260,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
parentIdTmp = Long.valueOf(modelData); parentIdTmp = Long.valueOf(modelData);
count.inc(); count.inc();
} catch (final NumberFormatException ex) { } catch (final NumberFormatException ex) {
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value); final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
parendUuidTmp = idList.get(0); parendUuidTmp = idList.get(0);
count.inc(); count.inc();
} }
@ -279,7 +284,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
// In the lazy mode, the request is done in asynchronous mode, they will be done after... // In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> { final LazyGetter lambda = () -> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(mappingKey, "=", parentId))); new Condition(new QueryCondition(mappingKey, "=", parentId)));
if (foreignData == null) { if (foreignData == null) {
return; return;
@ -290,7 +295,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
} else if (parendUuid != null) { } else if (parendUuid != null) {
final LazyGetter lambda = () -> { final LazyGetter lambda = () -> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(mappingKey, "=", parendUuid))); new Condition(new QueryCondition(mappingKey, "=", parendUuid)));
if (foreignData == null) { if (foreignData == null) {
return; return;
@ -303,18 +308,4 @@ public class AddOnOneToMany implements DataAccessAddOn {
} }
} }
// TODO : refacto this table to manage a generic table with dynamic name to be serialize with the default system
@Override
public void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId) throws Exception {
// This is a remote field ==> nothing to generate (it is stored in the remote object
}
} }

View File

@ -0,0 +1,158 @@
package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
import jakarta.validation.constraints.NotNull;
public interface DataAccessAddOn {
/** 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. */
default String getSQLFieldType(final Field elem, final QueryOptions options) throws Exception {
return null;
}
/** 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);
/** Insert data in the specific field (the field must be in the current db, otherwiise it does not work at all.
* @param ps DB statement interface.
* @param data The date to inject.
* @param iii The index of injection
* @return the new index of injection in case of multiple value management
* @throws SQLException */
void insertData(final DBAccessSQL ioDb, PreparedStatement ps, final Field field, Object data, CountInOut iii)
throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
/** Element can insert in the single request
* @param field
* @return */
default boolean canInsert(final Field field) {
return false;
}
/** Element can be retrieve with the specific mode
* @param field
* @return */
default boolean canRetrieve(final Field field) {
return false;
}
void generateQuery(
@NotNull String tableName,
@NotNull final String primaryKey,
@NotNull Field field,
@NotNull final StringBuilder querySelect,
@NotNull final StringBuilder query,
@NotNull String name,
@NotNull CountInOut count,
QueryOptions options) throws Exception;
// Return the number of colomn read
void fillFromQuery(
final DBAccessSQL ioDb,
ResultSet rs,
Field field,
Object data,
CountInOut count,
QueryOptions options,
final List<LazyGetter> lazyCall)
throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
/** Create associated table of the specific element.
* @param tableName
* @param elem
* @param mainTableBuilder
* @param ListOtherTables
* @param createIfNotExist
* @param createDrop
* @param fieldId
* @throws Exception */
default void createTables(
final String tableName,
final Field primaryField,
final Field field,
final StringBuilder mainTableBuilder,
final List<String> preActionList,
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
}
/** Some action must be done asynchronously for update or remove element
* @param field
* @return */
default boolean isInsertAsync(final Field field) throws Exception {
return false;
}
/** When insert is mark async, this function permit to create or update the data
* @param tableName Name of the Table.
* @param localId Local ID of the current table
* @param field Field that is updated.
* @param data Data that might be inserted.
* @param actions Asynchronous action to do after main request. */
default void asyncInsert(
final DBAccessSQL ioDb,
final String tableName,
final Object localId,
final Field field,
final Object data,
final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
}
/** Some action must be done asynchronously for update or remove element
* @param field
* @return */
default boolean isUpdateAsync(final Field field) throws Exception {
return false;
}
/** When insert is mark async, this function permit to create or update the data
* @param tableName Name of the Table.
* @param localId Local ID of the current table
* @param field Field that is updated.
* @param data Data that might be inserted.
* @param actions Asynchronous action to do after main request. */
default void asyncUpdate(
final DBAccessSQL ioDb,
final String tableName,
final Object localId,
final Field field,
final Object data,
final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
}
default void drop(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception {
}
default void cleanAll(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception {
}
}

View File

@ -0,0 +1,25 @@
package org.kar.archidata.dataAccess.addOnSQL.model;
import org.kar.archidata.model.OIDGenericDataSoftDelete;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
public class LinkTableGeneric extends OIDGenericDataSoftDelete {
public LinkTableGeneric() {
// nothing to do...
}
public LinkTableGeneric(final Object object1Id, final Object object2Id) {
this.object1Id = object1Id;
this.object2Id = object2Id;
}
@Schema(description = "Object reference 1")
@Column(nullable = false)
public Object object1Id;
@Schema(description = "Object reference 2")
@Column(nullable = false)
public Object object2Id;
}

View File

@ -0,0 +1,25 @@
package org.kar.archidata.dataAccess.addOnSQL.model;
import java.util.List;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class TableCoversGeneric {
public TableCoversGeneric() {
// nothing to do...
}
public TableCoversGeneric(final Object id, final List<Object> covers) {
this.id = id;
this.covers = covers;
}
@Id
public Object id;
@DataJson()
public List<Object> covers;
}

View File

@ -3,6 +3,7 @@ package org.kar.archidata.dataAccess.options;
import java.util.List; import java.util.List;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
@ -12,11 +13,16 @@ public interface CheckFunctionInterface {
* @param data The object that might be injected. * @param data The object that might be injected.
* @param modifiedValue List of fields that might be check. If null, then all column must be checked. * @param modifiedValue List of fields that might be check. If null, then all column must be checked.
* @throws Exception Exception is generate if the data are incorrect. */ * @throws Exception Exception is generate if the data are incorrect. */
void check(final String baseName, Object data, List<String> modifiedValue, final QueryOptions options) void check(
throws Exception; final DBAccess ioDb,
final String baseName,
Object data,
List<String> modifiedValue,
final QueryOptions options) throws Exception;
default void checkAll(final String baseName, final Object data, final QueryOptions options) throws Exception { default void checkAll(final DBAccess ioDb, final String baseName, final Object data, final QueryOptions options)
check(baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options); throws Exception {
check(ioDb, baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options);
} }
} }

View File

@ -2,12 +2,14 @@ package org.kar.archidata.dataAccess.options;
import java.util.List; import java.util.List;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
public class CheckFunctionVoid implements CheckFunctionInterface { public class CheckFunctionVoid implements CheckFunctionInterface {
@Override @Override
public void check( public void check(
final DBAccess ioDb,
final String baseName, final String baseName,
final Object data, final Object data,
final List<String> filterValue, final List<String> filterValue,

View File

@ -14,6 +14,7 @@ import java.util.regex.Pattern;
import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.DataJson; import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
@ -35,18 +36,29 @@ public class CheckJPA<T> implements CheckFunctionInterface {
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
public interface CheckInterface<K> { public interface CheckInterface<K> {
/** This function implementation is design to check if the updated class is valid of not for insertion /** This function implementation is design to check if the updated class is valid of not for insertion
* @param ioDb Access on the Data-Base
* @param baseName Base of the name input that is displayed in exception generated. * @param baseName Base of the name input that is displayed in exception generated.
* @param data The object that might be injected. * @param data The object that might be injected.
* @param modifiedValue List of fields that modification is requested. * @param modifiedValue List of fields that modification is requested.
* @param options Some query option that the checker can need to generate basic check. * @param options Some query option that the checker can need to generate basic check.
* @throws Exception Exception is generate if the data are incorrect. */ * @throws Exception Exception is generate if the data are incorrect. */
void check(final String baseName, final K data, List<String> modifiedValue, final QueryOptions options) void check(
throws Exception; final DBAccess ioDb,
final String baseName,
final K data,
List<String> modifiedValue,
final QueryOptions options) throws Exception;
} }
protected Map<String, List<CheckInterface<T>>> checking = null; protected Map<String, List<CheckInterface<T>>> checking = null;
protected void add(final String field, final CheckInterface<T> checkFunction) { protected void add(final String field, final CheckInterface<T> checkFunction) throws DataAccessException {
if (!AnnotationTools.hasFieldsName(this.clazz, field)) {
LOGGER.error("Try to add a JPA Filter on an inexistant Field: '{}' not in {}", field,
AnnotationTools.getAllFieldsNames(this.clazz));
throw new DataAccessException("Try to add a JPA Filter on an inexistant Field: '" + field + "' not in "
+ AnnotationTools.getAllFieldsNames(this.clazz));
}
List<CheckInterface<T>> actions = this.checking.get(field); List<CheckInterface<T>> actions = this.checking.get(field);
if (actions == null) { if (actions == null) {
actions = new ArrayList<>(); actions = new ArrayList<>();
@ -72,6 +84,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (AnnotationTools.isPrimaryKey(field)) { if (AnnotationTools.isPrimaryKey(field)) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -83,6 +96,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (AnnotationTools.getConstraintsNotNull(field)) { if (AnnotationTools.getConstraintsNotNull(field)) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -95,6 +109,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) { if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -109,6 +124,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (maxValue != null) { if (maxValue != null) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -128,6 +144,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (minValue != null) { if (minValue != null) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -147,6 +164,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -173,6 +191,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final int maxValue = maxValueRoot.intValue(); final int maxValue = maxValueRoot.intValue();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -193,6 +212,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final int minValue = minValueRoot.intValue(); final int minValue = minValueRoot.intValue();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -212,6 +232,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -232,6 +253,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -255,6 +277,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final float maxValue = maxValueRoot.floatValue(); final float maxValue = maxValueRoot.floatValue();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -275,6 +298,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final float minValue = minValueRoot.floatValue(); final float minValue = minValueRoot.floatValue();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -296,6 +320,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final double maxValue = maxValueRoot.doubleValue(); final double maxValue = maxValueRoot.doubleValue();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -316,6 +341,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final double minValue = minValueRoot.doubleValue(); final double minValue = minValueRoot.doubleValue();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -342,6 +368,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (maxSizeString > 0) { if (maxSizeString > 0) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -361,6 +388,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
if (limitSize != null) { if (limitSize != null) {
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -385,6 +413,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final Pattern pattern = Pattern.compile(patternString); final Pattern pattern = Pattern.compile(patternString);
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -406,6 +435,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final Pattern pattern = Pattern.compile(emailPattern); final Pattern pattern = Pattern.compile(emailPattern);
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -430,21 +460,39 @@ public class CheckJPA<T> implements CheckFunctionInterface {
.newInstance(); .newInstance();
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
final QueryOptions options) -> { final QueryOptions options) -> {
instance.checkAll(baseName + fieldName + ".", field.get(data), options); instance.checkAll(ioDb, baseName + fieldName + ".", field.get(data), options);
}); });
} }
} else if (type.isEnum()) { } else if (type.isEnum()) {
// nothing to do. // nothing to do.
} }
final DataJson dataJson = AnnotationTools.getDataJson(field);
if (dataJson != null && dataJson.checker() != null) {
final CheckFunctionInterface checkerInstance = dataJson.checker().getDeclaredConstructor()
.newInstance();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
// get the field of the specific element
final Object tmpData = field.get(data);
checkerInstance.check(ioDb, baseName, tmpData, null, options);
});
}
// keep this is last ==> take more time... // keep this is last ==> take more time...
if (AnnotationTools.isUnique(field)) { if (AnnotationTools.isUnique(field)) {
// Create the request ... // Create the request ...
add(fieldName, add(fieldName,
( (
final DBAccess ioDb,
final String baseName, final String baseName,
final T data, final T data,
final List<String> modifiedValue, final List<String> modifiedValue,
@ -472,15 +520,36 @@ public class CheckJPA<T> implements CheckFunctionInterface {
} }
} }
public void check(final Object data) throws Exception {
check(null, "", data, null, null);
}
public void check(final String baseName, final Object data) throws Exception {
check(null, baseName, data, null, null);
}
public void check(final DBAccess ioDb, final String baseName, final Object data) throws Exception {
check(ioDb, baseName, data, null, null);
}
public void check(final DBAccess ioDb, final String baseName, final Object data, final List<String> modifiedValue)
throws Exception {
check(ioDb, baseName, data, modifiedValue, null);
}
@Override @Override
public void check( public void check(
final DBAccess ioDb,
final String baseName, final String baseName,
final Object data, final Object data,
final List<String> modifiedValue, List<String> modifiedValue,
final QueryOptions options) throws Exception { final QueryOptions options) throws Exception {
if (this.checking == null) { if (this.checking == null) {
initialize(); initialize();
} }
if (modifiedValue == null) {
modifiedValue = AnnotationTools.getAllFieldsNames(this.clazz);
}
if (!(this.clazz.isAssignableFrom(data.getClass()))) { if (!(this.clazz.isAssignableFrom(data.getClass()))) {
throw new DataAccessException("Incompatatyble type of Object" + data.getClass().getCanonicalName()); throw new DataAccessException("Incompatatyble type of Object" + data.getClass().getCanonicalName());
} }
@ -492,7 +561,7 @@ public class CheckJPA<T> implements CheckFunctionInterface {
continue; continue;
} }
for (final CheckInterface<T> action : actions) { for (final CheckInterface<T> action : actions) {
action.check(baseName, dataCasted, modifiedValue, options); action.check(ioDb, baseName, dataCasted, modifiedValue, options);
} }
} }
checkTyped(dataCasted, modifiedValue, options); checkTyped(dataCasted, modifiedValue, options);
@ -502,4 +571,5 @@ public class CheckJPA<T> implements CheckFunctionInterface {
throws Exception { throws Exception {
// nothing to do ... // nothing to do ...
} }
} }

View File

@ -1,11 +1,17 @@
package org.kar.archidata.dataAccess.options; package org.kar.archidata.dataAccess.options;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import org.bson.conversions.Bson;
import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.QueryItem; import org.kar.archidata.dataAccess.QueryItem;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import com.mongodb.client.model.Filters;
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */ /** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
public class Condition extends QueryOption { public class Condition extends QueryOption {
public final QueryItem condition; public final QueryItem condition;
@ -24,9 +30,9 @@ public class Condition extends QueryOption {
} }
} }
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
if (this.condition != null) { if (this.condition != null) {
this.condition.injectQuery(ps, iii); this.condition.injectQuery(ioDb, ps, iii);
} }
} }
@ -62,4 +68,26 @@ public class Condition extends QueryOption {
} }
query.append("\n"); query.append("\n");
} }
public Bson getFilter(final String collectionName, final QueryOptions options, final String deletedFieldName) {
boolean exclude_deleted = true;
if (options != null) {
exclude_deleted = !options.exist(AccessDeletedItems.class);
}
final List<Bson> filter = new ArrayList<>();
if (exclude_deleted && deletedFieldName != null) {
filter.add(Filters.eq(deletedFieldName, false));
}
// Check if we have a condition to generate
if (this.condition != null) {
this.condition.generateFilter(filter);
}
if (filter.size() == 0) {
return null;
}
if (filter.size() == 1) {
return filter.get(0);
}
return Filters.and(filter.toArray(new Bson[0]));
}
} }

View File

@ -1,51 +0,0 @@
package org.kar.archidata.dataAccess.options;
import java.io.IOException;
import java.util.List;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.db.DBConfig;
import org.kar.archidata.db.DBEntry;
public class DBInterfaceOption extends QueryOption {
private DBEntry entry = null;
private final DBConfig config;
private final boolean root;
public DBInterfaceOption(final DBConfig config) {
this.config = config;
this.root = false;
}
public DBInterfaceOption(final DBConfig config, final boolean root) {
this.config = config;
this.root = root;
}
public DBEntry getEntry(final QueryOptions options) throws IOException {
if (this.entry == null) {
final List<DBInterfaceRoot> isRoot = options.get(DBInterfaceRoot.class);
this.entry = DBEntry.createInterface(this.config, isRoot.size() == 1 && isRoot.get(0).getRoot());
}
return this.entry;
}
public boolean getRoot() {
return this.root;
}
public static DBEntry getAutoEntry(final QueryOptions options) throws IOException {
if (options == null) {
return DBEntry.createInterface(GlobalConfiguration.dbConfig, false);
}
final List<DBInterfaceOption> dbOption = options.get(DBInterfaceOption.class);
if (dbOption.size() == 0) {
final List<DBInterfaceRoot> isRoot = options.get(DBInterfaceRoot.class);
return DBEntry.createInterface(GlobalConfiguration.dbConfig, isRoot.size() == 1 && isRoot.get(0).getRoot());
} else {
return dbOption.get(0).getEntry(options);
}
}
}

View File

@ -3,7 +3,7 @@ package org.kar.archidata.dataAccess.options;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
public class Limit extends QueryOption { public class Limit extends QueryOption {
protected final long limit; protected final long limit;
@ -16,8 +16,12 @@ public class Limit extends QueryOption {
query.append(" LIMIT ? \n"); query.append(" LIMIT ? \n");
} }
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
DataAccess.addElement(ps, this.limit, iii); ioDb.addElement(ps, this.limit, iii);
iii.inc(); iii.inc();
} }
public long getValue() {
return this.limit;
}
} }

View File

@ -0,0 +1,12 @@
package org.kar.archidata.dataAccess.options;
public class OptionRenameColumn extends QueryOption {
public final String columnName;
public final String colomnNewName;
public OptionRenameColumn(final String name, final String newName) {
this.columnName = name;
this.colomnNewName = newName;
}
}

View File

@ -0,0 +1,20 @@
package org.kar.archidata.dataAccess.options;
public class OptionSpecifyType extends QueryOption {
public final String name;
public final Class<?> clazz;
public final boolean isList;
// To specify the type of an element if the model is a Object.
public OptionSpecifyType(final String name, final Class<?> clazz) {
this.clazz = clazz;
this.name = name;
this.isList = false;
}
public OptionSpecifyType(final String name, final Class<?> clazz, final boolean isList) {
this.clazz = clazz;
this.name = name;
this.isList = isList;
}
}

View File

@ -3,7 +3,9 @@ package org.kar.archidata.dataAccess.options;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;
import org.bson.Document;
import org.kar.archidata.dataAccess.CountInOut; import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.options.OrderItem.Order;
public class OrderBy extends QueryOption { public class OrderBy extends QueryOption {
protected final List<OrderItem> childs; protected final List<OrderItem> childs;
@ -40,4 +42,10 @@ public class OrderBy extends QueryOption {
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception { public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
// nothing to add. // nothing to add.
} }
public void generateSort(final Document data) {
for (final OrderItem elem : this.childs) {
data.append(elem.value, elem.order == Order.ASC ? 1 : -1);
}
}
} }

View File

@ -1,92 +0,0 @@
package org.kar.archidata.db;
import org.kar.archidata.dataAccess.DataAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DBConfig {
static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.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(final String type, final String hostname, final Integer port, final String login,
final String password, final String dbName, final 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='" + this.type + '\'' + ", hostname='" + this.hostname + '\'' + ", port=" + this.port
+ ", login='" + this.login + '\'' + ", password='" + this.password + '\'' + ", dbName='" + this.dbName
+ "' }";
}
public String getHostname() {
return this.hostname;
}
public int getPort() {
return this.port;
}
public String getLogin() {
return this.login;
}
public String getPassword() {
return this.password;
}
public String getDbName() {
return this.dbName;
}
public boolean getKeepConnected() {
return this.keepConnected;
}
public String getUrl() {
return getUrl(false);
}
public String getUrl(final boolean isRoot) {
if (this.type.equals("sqlite")) {
if (isRoot) {
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";
}
}

View File

@ -1,95 +0,0 @@
package org.kar.archidata.db;
import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
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<DBEntry> stored = new ArrayList<>();
private DBEntry(final DBConfig config, final boolean root) throws IOException {
this.config = config;
if (root) {
connectRoot();
} else {
connect();
}
}
public static DBEntry createInterface(final DBConfig config) throws IOException {
return createInterface(config, false);
}
public static DBEntry createInterface(final DBConfig config, final boolean root) throws IOException {
if (config.getKeepConnected()) {
for (final DBEntry elem : stored) {
if (elem == null) {
continue;
}
if (elem.config.getUrl().equals(config.getUrl())) {
return elem;
}
}
final DBEntry tmp = new DBEntry(config, root);
stored.add(tmp);
return tmp;
} else {
return new DBEntry(config, root);
}
}
public void connectRoot() throws IOException {
try {
this.connection = DriverManager.getConnection(this.config.getUrl(true), this.config.getLogin(),
this.config.getPassword());
} catch (final SQLException ex) {
throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true));
}
}
public void connect() throws IOException {
try {
this.connection = DriverManager.getConnection(this.config.getUrl(), this.config.getLogin(),
this.config.getPassword());
} catch (final SQLException ex) {
LOGGER.error("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true));
throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + this.config.getUrl(true));
}
}
@Override
public void close() throws IOException {
if (this.config.getKeepConnected()) {
return;
}
closeForce();
}
public void closeForce() throws IOException {
try {
// connection.commit();
this.connection.close();
} catch (final SQLException ex) {
throw new IOException("Dis-connection db fail: " + ex.getMessage());
}
}
public static void closeAllForceMode() throws IOException {
for (final DBEntry entry : stored) {
entry.closeForce();
}
stored = new ArrayList<>();
}
}

View File

@ -0,0 +1,165 @@
package org.kar.archidata.db;
import java.util.List;
import java.util.Objects;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DbConfig {
static final Logger LOGGER = LoggerFactory.getLogger(DBAccess.class);
private final String type;
private final String hostname;
private final Short port;
private final String login;
private final String password;
private String dbName;
private final boolean keepConnected;
private final List<Class<?>> classes;
public DbConfig() throws DataAccessException {
this(ConfigBaseVariable.getDBType(), ConfigBaseVariable.getDBHost(), ConfigBaseVariable.getDBPort(),
ConfigBaseVariable.getDBLogin(), ConfigBaseVariable.getDBPassword(), ConfigBaseVariable.getDBName(),
ConfigBaseVariable.getDBKeepConnected(), List.of(ConfigBaseVariable.getBbInterfacesClasses()));
}
public DbConfig(final String type, final String hostname, final Short port, final String login,
final String password, final String dbName, final boolean keepConnected, final List<Class<?>> classes)
throws DataAccessException {
if (type == null) {
this.type = "mysql";
} else {
if (!"mysql".equals(type) && !"sqlite".equals(type) && !"mongo".equals(type)) {
throw new DataAccessException("unexpected DB type: '" + type + "'");
}
this.type = type;
}
if (hostname == null) {
this.hostname = "localhost";
} else {
this.hostname = hostname;
}
if (port == null) {
if ("mysql".equals(this.type)) {
this.port = 3306;
} else {
this.port = 27017;
}
} else {
this.port = port;
}
this.login = login;
this.password = password;
this.dbName = dbName;
this.keepConnected = keepConnected;
this.classes = classes;
}
@Override
public String toString() {
return "DBConfig{type='" + this.type + '\'' + ", hostname='" + this.hostname + '\'' + ", port=" + this.port
+ ", login='" + this.login + '\'' + ", password='" + this.password + '\'' + ", dbName='" + this.dbName
+ "' }";
}
public String getHostname() {
return this.hostname;
}
public String getType() {
return this.type;
}
public int getPort() {
return this.port;
}
public String getLogin() {
return this.login;
}
public String getPassword() {
return this.password;
}
public String getDbName() {
return this.dbName;
}
public void setDbName(final String dbName) {
this.dbName = dbName;
}
public boolean getKeepConnected() {
return this.keepConnected;
}
public List<Class<?>> getClasses() {
return this.classes;
}
public String getUrl() {
if (this.type.equals("sqlite")) {
if (this.hostname.equals("memory")) {
return "jdbc:sqlite::memory:";
}
return "jdbc:sqlite:" + this.hostname + ".db";
}
if ("mongo".equals(this.type)) {
return "mongodb://" + getLogin() + ":" + getPassword() + "@" + this.hostname + ":" + this.port;
}
if ("mysql".equals(this.type)) {
if (this.dbName == null || this.dbName.isEmpty()) {
LOGGER.warn("Request log on SQL: root");
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";
}
return "dead_code";
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
if (other instanceof final DbConfig dbConfig) {
return Objects.equals(this.port, dbConfig.port) //
&& this.keepConnected == dbConfig.keepConnected //
&& Objects.equals(this.type, dbConfig.type) //
&& Objects.equals(this.hostname, dbConfig.hostname) //
&& Objects.equals(this.login, dbConfig.login) //
&& Objects.equals(this.password, dbConfig.password) //
&& Objects.equals(this.dbName, dbConfig.dbName) //
&& Objects.equals(this.classes, dbConfig.classes);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(this.type, this.hostname, this.port, this.login, this.password, this.dbName,
this.keepConnected, this.classes);
}
@Override
public DbConfig clone() {
try {
return new DbConfig(this.type, this.hostname, this.port, this.login, this.password, this.dbName,
this.keepConnected, this.classes);
} catch (final DataAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,82 @@
package org.kar.archidata.db;
import java.io.Closeable;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class DbIo implements Closeable {
private final static Logger LOGGER = LoggerFactory.getLogger(DbIo.class);
// we count the number of connection in the system to prevent disconnection in a middle of a stream.
private int count = 0;
private static int idCount = 0;
protected final int id;
protected final DbConfig config;
protected DbIo(final DbConfig config) throws IOException {
this.id = idCount;
idCount += 10;
this.config = config;
}
@Override
public synchronized final void close() throws IOException {
LOGGER.trace("[{}] Request close count={}", this.id, this.count);
if (this.count <= 0) {
LOGGER.error("[{}] Request one more close", this.id);
return;
}
this.count--;
if (this.count == 0) {
LOGGER.trace("[{}] close", this.id);
closeImplement();
} else {
LOGGER.trace("[{}] postponed close", this.id);
}
}
public synchronized final void closeForce() throws IOException {
LOGGER.trace("[{}] Request Force close count={}", this.id, this.count);
if (this.count == 0) {
LOGGER.trace("[{}] Nothing to do in force close, DB is already closed", this.id);
return;
}
if (this.config.getKeepConnected()) {
if (this.count >= 2) {
LOGGER.error("[{}] Force close: with {} connection on it", this.id, this.count - 1);
}
} else if (this.count >= 1) {
LOGGER.error("[{}] Force close: with {} connection on it", this.id, this.count);
}
this.count = 0;
LOGGER.trace("[{}] Force close", this.id);
closeImplement();
}
public synchronized final void open() throws IOException {
LOGGER.trace("[{}] Request open count={}", this.id, this.count);
if (this.count == 0) {
LOGGER.trace("[{}] open", this.id);
openImplement();
} else {
LOGGER.trace("[{}] open: already done", this.id);
}
this.count++;
}
protected abstract void closeImplement() throws IOException;
protected abstract void openImplement() throws IOException;
public boolean compatible(final DbConfig config) {
return this.config.equals(config);
}
public DbConfig getCongig() {
return this.config;
}
}

View File

@ -0,0 +1,65 @@
package org.kar.archidata.db;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DbIoFactory {
final static Logger LOGGER = LoggerFactory.getLogger(DbIoFactory.class);
private static List<DbIo> dbIoStored = new ArrayList<>();
private DbIoFactory() throws IOException {}
public static DbIo create() throws IOException, DataAccessException {
// Find the global configuration of the system.
return create(new DbConfig());
}
public static DbIo create(final DbConfig config) throws IOException {
for (final DbIo dbIo : dbIoStored) {
if (dbIo == null) {
continue;
}
if (dbIo.compatible(config)) {
dbIo.open();
return dbIo;
}
}
final DbIo dbIo = createInstance(config);
if (config.getKeepConnected()) {
dbIo.open();
dbIoStored.add(dbIo);
}
return dbIo;
}
private static DbIo createInstance(final DbConfig config) throws IOException {
switch (config.getType()) {
case "mysql":
return new DbIoSql(config);
case "sqlite":
return new DbIoSql(config);
case "mongo":
return new DbIoMorphia(config);
}
throw new IOException("DB type: '" + config.getType() + "'is not managed");
}
public static void close() throws IOException {
for (final DbIo dbIo : dbIoStored) {
dbIo.close();
}
}
public static void closeAllForceMode() throws IOException {
for (final DbIo entry : dbIoStored) {
entry.closeForce();
}
dbIoStored = new ArrayList<>();
}
}

View File

@ -0,0 +1,83 @@
package org.kar.archidata.db;
import java.io.Closeable;
import java.io.IOException;
import org.bson.UuidRepresentation;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.kar.archidata.converter.morphia.SqlTimestampCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import dev.morphia.Datastore;
import dev.morphia.Morphia;
public class DbIoMorphia extends DbIo implements Closeable {
private final static Logger LOGGER = LoggerFactory.getLogger(DbIoMorphia.class);
private MongoClient mongoClient = null;
private Datastore datastore = null;
public DbIoMorphia(final DbConfig config) throws IOException {
super(config);
}
public Datastore getDatastore() {
return this.datastore;
}
public MongoClient getClient() {
return this.mongoClient;
}
@Override
synchronized public void closeImplement() throws IOException {
this.mongoClient.close();
this.mongoClient = null;
this.datastore = null;
}
@Override
synchronized public void openImplement() throws IOException {
final Class<?>[] classes = this.config.getClasses().toArray(new Class<?>[0]);
final String dbUrl = this.config.getUrl();
final String dbName = this.config.getDbName();
// Connect to MongoDB (simple form):
// final MongoClient mongoClient = MongoClients.create(dbUrl);
LOGGER.info("Connect on the DB: {}", dbUrl);
// Connect to MongoDB (complex form):
final ConnectionString connectionString = new ConnectionString(dbUrl);
// Créer un CodecRegistry pour UUID
//final CodecRegistry uuidCodecRegistry = CodecRegistries.fromCodecs(new UUIDCodec());
final CodecRegistry SqlTimestampCodecRegistry = CodecRegistries.fromCodecs(new SqlTimestampCodec());
// Créer un CodecRegistry pour POJOs
final CodecRegistry pojoCodecRegistry = CodecRegistries
.fromProviders(PojoCodecProvider.builder().automatic(true).build());
// Ajouter le CodecRegistry par défaut, le codec UUID et celui pour POJOs
//final CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
// MongoClientSettings.getDefaultCodecRegistry(), /*uuidCodecRegistry, */ pojoCodecRegistry);
final CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
MongoClientSettings.getDefaultCodecRegistry(),
CodecRegistries.fromCodecs(new org.bson.codecs.UuidCodec(UuidRepresentation.STANDARD)),
pojoCodecRegistry, SqlTimestampCodecRegistry);
// Configurer MongoClientSettings
final MongoClientSettings clientSettings = MongoClientSettings.builder() //
.applyConnectionString(connectionString)//
.codecRegistry(codecRegistry) //
.uuidRepresentation(UuidRepresentation.STANDARD)//
.build();
this.mongoClient = MongoClients.create(clientSettings);
this.datastore = Morphia.createDatastore(this.mongoClient, dbName);
// Map entities
this.datastore.getMapper().map(classes);
// Ensure indexes
this.datastore.ensureIndexes();
}
}

View File

@ -0,0 +1,56 @@
package org.kar.archidata.db;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DbIoSql extends DbIo {
final static Logger LOGGER = LoggerFactory.getLogger(DbIoSql.class);
private Connection connection = null;
public DbIoSql(final DbConfig config) throws IOException {
super(config);
}
public Connection getConnection() {
if (this.connection == null) {
LOGGER.error("[{}] Retrieve a closed connection !!!", this.id);
}
return this.connection;
}
@Override
synchronized public void openImplement() throws IOException {
final String dbUrl = this.config.getUrl();
final String login = this.config.getLogin();
final String password = this.config.getPassword();
try {
this.connection = DriverManager.getConnection(dbUrl, login, password);
} catch (final SQLException ex) {
LOGGER.error("Connection db fail: " + ex.getMessage() + " On URL: " + dbUrl);
throw new IOException("Connection db fail: " + ex.getMessage() + " On URL: " + dbUrl);
}
if (this.connection == null) {
throw new IOException("Connection db fail: NULL On URL: " + dbUrl);
}
}
@Override
synchronized public void closeImplement() throws IOException {
if (this.connection == null) {
LOGGER.error("Request close of un-open connection !!!");
return;
}
try {
this.connection.close();
this.connection = null;
} catch (final SQLException ex) {
throw new IOException("Dis-connection db fail: " + ex.getMessage());
}
}
}

View File

@ -17,6 +17,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.ContentDisposition; import org.glassfish.jersey.media.multipart.ContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.catcher.RestErrorResponse; import org.kar.archidata.catcher.RestErrorResponse;
@ -157,6 +158,12 @@ public class TsGenerateApi {
tsModels.add(new TsClassElement(models, "ZodUUID", "UUID", "isUUID", "zod.string().uuid()", tsModels.add(new TsClassElement(models, "ZodUUID", "UUID", "isUUID", "zod.string().uuid()",
DefinedPosition.BASIC)); DefinedPosition.BASIC));
} }
models = api.getCompatibleModels(List.of(ObjectId.class));
if (models != null) {
tsModels.add(new TsClassElement(models, "ZodObjectId", "ObjectId", "isObjectId",
"zod.string().length(24, \"Invalid ObjectId length\").regex(/^[a-fA-F0-9]{24}$/, \"Invalid ObjectId format\")",
DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Long.class, long.class)); models = api.getCompatibleModels(List.of(Long.class, long.class));
if (models != null) { if (models != null) {
tsModels.add( tsModels.add(

View File

@ -44,7 +44,7 @@ public class ClassObjectModel extends ClassModel {
for (final Field field : superClass.getFields()) { for (final Field field : superClass.getFields()) {
String name; String name;
try { try {
name = AnnotationTools.getFieldName(field); name = AnnotationTools.getFieldNameRaw(field);
if (filedName.equals(name)) { if (filedName.equals(name)) {
return true; return true;
} }
@ -136,7 +136,7 @@ public class ClassObjectModel extends ClassModel {
this(field.getName(), // this(field.getName(), //
ClassModel.getModel(field.getGenericType(), previous), // ClassModel.getModel(field.getGenericType(), previous), //
getSubModelIfExist(field, previous), // getSubModelIfExist(field, previous), //
AnnotationTools.getComment(field), // AnnotationTools.getSchemaDescription(field), //
getStringMinSize(field), // getStringMinSize(field), //
getStringMaxSize(field), // getStringMaxSize(field), //
AnnotationTools.getConstraintsMin(field), // AnnotationTools.getConstraintsMin(field), //
@ -217,7 +217,7 @@ public class ClassObjectModel extends ClassModel {
} }
alreadyAdded.add(dataName); alreadyAdded.add(dataName);
LOGGER.trace(" + '{}'", elem.getName()); LOGGER.trace(" + '{}'", elem.getName());
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldNameRaw(elem), elem.getType());
final FieldProperty porperty = new FieldProperty(elem, previous); final FieldProperty porperty = new FieldProperty(elem, previous);
for (final ClassModel depModel : porperty.model().getAlls()) { for (final ClassModel depModel : porperty.model().getAlls()) {
if (!this.dependencyModels.contains(depModel)) { if (!this.dependencyModels.contains(depModel)) {

View File

@ -19,4 +19,11 @@ public class GenericContext implements Principal {
} }
return this.userByToken.name; return this.userByToken.name;
} }
public Long getUserID() {
if (this.userByToken != null) {
return this.userByToken.id;
}
return null;
}
} }

View File

@ -1,5 +1,7 @@
package org.kar.archidata.migration; package org.kar.archidata.migration;
import org.kar.archidata.dataAccess.DBAccess;
public interface AsyncCall { public interface AsyncCall {
void doRequest() throws Exception; void doRequest(DBAccess da) throws Exception;
} }

View File

@ -5,16 +5,17 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.db.DBConfig; import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.migration.model.Migration; import org.kar.archidata.migration.model.Migration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.ws.rs.InternalServerErrorException;
public class MigrationEngine { public class MigrationEngine {
final static Logger LOGGER = LoggerFactory.getLogger(MigrationEngine.class); final static Logger LOGGER = LoggerFactory.getLogger(MigrationEngine.class);
@ -52,17 +53,17 @@ public class MigrationEngine {
/** Get the current version/migration name /** Get the current version/migration name
* @return Model represent the last migration. If null then no migration has been done. * @return Model represent the last migration. If null then no migration has been done.
* @throws MigrationException */ * @throws MigrationException */
public Migration getCurrentVersion() throws MigrationException { public Migration getCurrentVersion(final DBAccess da) throws MigrationException {
if (!DataAccess.isTableExist("KAR_migration")) { if (!da.isTableExist("KAR_migration")) {
return null; return null;
} }
try { try {
List<Migration> data = null; List<Migration> data = null;
try { try {
data = DataAccess.gets(Migration.class, QueryOptions.READ_ALL_COLOMN); data = da.gets(Migration.class, QueryOptions.READ_ALL_COLOMN);
} catch (final Exception e) { } catch (final Exception e) {
// Previous version does not have the same timeCode... // Previous version does not have the same timeCode...
data = DataAccess.gets(Migration.class); data = da.gets(Migration.class);
} }
if (data == null) { 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:{}");
@ -87,7 +88,7 @@ public class MigrationEngine {
/** Process the automatic migration of the system The function wait the Administrator intervention to correct the bug. /** Process the automatic migration of the system The function wait the Administrator intervention to correct the bug.
* @param config SQL connection for the migration. * @param config SQL connection for the migration.
* @throws InterruptedException user interrupt the migration */ * @throws InterruptedException user interrupt the migration */
public void migrateWaitAdmin(final DBConfig config) throws InterruptedException { public void migrateWaitAdmin(final DbConfig config) throws InterruptedException {
try { try {
migrateErrorThrow(config); migrateErrorThrow(config);
} catch (final Exception ex) { } catch (final Exception ex) {
@ -102,13 +103,7 @@ public class MigrationEngine {
} }
} }
/** Process the automatic migration of the system private void listAvailableMigration() throws MigrationException {
* @param config SQL connection for the migration
* @throws IOException Error if access on the DB */
@SuppressFBWarnings({ "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING",
"SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" })
public void migrateErrorThrow(final DBConfig config) throws MigrationException {
LOGGER.info("Execute migration ... [BEGIN]");
// check the integrity of the migrations: // check the integrity of the migrations:
LOGGER.info("List of availlable Migration: "); LOGGER.info("List of availlable Migration: ");
for (final MigrationInterface elem : this.datas) { for (final MigrationInterface elem : this.datas) {
@ -132,129 +127,154 @@ public class MigrationEngine {
} }
} }
} }
}
// STEP 1: Check the DB exist: private void createTableIfAbleOrWaitAdmin(final DbConfig configInput) throws MigrationException {
LOGGER.info("Verify existance of '{}'", config.getDbName()); final DbConfig config = configInput.clone();
boolean exist = DataAccess.isDBExist(config.getDbName()); config.setDbName(null);
if (!exist) { final String dbName = configInput.getDbName();
LOGGER.warn("DB: '{}' DOES NOT EXIST ==> create one", config.getDbName()); LOGGER.info("Verify existance of '{}'", dbName);
// create the local DB: try (final DBAccess da = DBAccess.createInterface(config)) {
DataAccess.createDB(config.getDbName()); boolean exist = da.isDBExist(dbName);
} if (!exist) {
exist = DataAccess.isDBExist(config.getDbName()); LOGGER.warn("DB: '{}' DOES NOT EXIST ==> create one", dbName);
while (!exist) { // create the local DB:
LOGGER.error("DB: '{}' DOES NOT EXIST after trying to create one ", config.getDbName()); da.createDB(dbName);
LOGGER.error("Waiting administrator create a new one, we check after 30 seconds...");
try {
Thread.sleep(30000);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
exist = DataAccess.isDBExist(config.getDbName()); exist = da.isDBExist(dbName);
} while (!exist) {
LOGGER.info("DB '{}' exist.", config.getDbName()); LOGGER.error("DB: '{}' DOES NOT EXIST after trying to create one ", dbName);
// STEP 2: Check migration table exist: LOGGER.error("Waiting administrator create a new one, we check after 30 seconds...");
LOGGER.info("Verify existance of migration table '{}'", "KAR_migration");
// TODO: set the class in parameters instead of string...
exist = DataAccess.isTableExist("KAR_migration");
if (!exist) {
LOGGER.info("'{}' Does not exist create a new one...", "KAR_migration");
// create the table:
List<String> sqlQuery;
try {
sqlQuery = DataFactory.createTable(Migration.class);
} catch (final Exception ex) {
ex.printStackTrace();
throw new MigrationException(
"Fail to create the local DB SQL model for migaration ==> wait administrator interventions");
}
LOGGER.info("Create Table with : {}", sqlQuery.get(0));
try {
DataAccess.executeQuery(sqlQuery.get(0));
} catch (SQLException | IOException ex) {
ex.printStackTrace();
throw new MigrationException(
"Fail to create the local DB model for migaration ==> wait administrator interventions");
}
}
final Migration currentVersion = getCurrentVersion();
List<MigrationInterface> toApply = new ArrayList<>();
boolean needPlaceholder = false;
if (currentVersion == null) {
// This is a first migration
LOGGER.info("First installation of the system ==> Create the DB");
if (this.init == null) {
// No initialization class ==> manage a historical creation mode...
toApply = this.datas;
} else {
// Select Initialization class if it exist
toApply.add(this.init);
needPlaceholder = true;
}
} else {
if (!currentVersion.terminated) {
throw new MigrationException("An error occured in the last migration: '" + currentVersion.name
+ "' defect @" + currentVersion.stepId + "/" + currentVersion.count);
}
LOGGER.info("Upgrade the system Current version: {}", currentVersion.name);
boolean find = this.init != null && this.init.getName().equals(currentVersion.name);
if (find) {
toApply = this.datas;
} else {
LOGGER.info(" ===> Check what must be apply:");
for (final MigrationInterface elem : this.datas) {
LOGGER.info(" - {}", elem.getName());
if (!find) {
if (currentVersion.name.equals(elem.getName())) {
LOGGER.info(" == current version");
find = true;
}
continue;
}
LOGGER.info(" ++ add ");
toApply.add(elem);
}
}
}
DBEntry entry;
try {
entry = DBEntry.createInterface(config);
final int id = 0;
final int count = toApply.size();
for (final MigrationInterface elem : toApply) {
migrateSingle(entry, elem, id, count);
}
} catch (final IOException e) {
e.printStackTrace();
throw new MigrationException("An error occured in the migration (can not access to the DB): '"
+ currentVersion.name + "' defect @" + currentVersion.stepId + "/" + currentVersion.count);
}
if (needPlaceholder) {
if (this.datas.size() == 0) {
// No placeholder needed, the model have no migration in the current version...
} else {
// we insert a placeholder to simulate the last migration is well done.
final String placeholderName = this.datas.get(this.datas.size() - 1).getName();
Migration migrationResult = new Migration();
migrationResult.id = 1000L;
migrationResult.name = placeholderName;
migrationResult.stepId = 0;
migrationResult.terminated = true;
migrationResult.count = 0;
migrationResult.log = "Place-holder for first initialization";
try { try {
migrationResult = DataAccess.insert(migrationResult); Thread.sleep(30000);
} catch (final Exception e) { } catch (final InterruptedException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
exist = da.isDBExist(dbName);
} }
} catch (final InternalServerErrorException e) {
e.printStackTrace();
throw new MigrationException("TODO ...");
} catch (final IOException e) {
e.printStackTrace();
throw new MigrationException("TODO ...");
} }
LOGGER.info("Execute migration ... [ END ]");
} }
public void migrateSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) /** Process the automatic migration of the system
* @param config SQL connection for the migration
* @throws IOException Error if access on the DB */
@SuppressFBWarnings({ "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING",
"SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" })
public void migrateErrorThrow(final DbConfig config) throws MigrationException {
LOGGER.info("Execute migration ... [BEGIN]");
listAvailableMigration();
// STEP 1: Check the DB exist:
createTableIfAbleOrWaitAdmin(config);
LOGGER.info("DB '{}' exist.", config.getDbName());
try (final DBAccess da = DBAccess.createInterface(config)) {
// STEP 2: Check migration table exist:
LOGGER.info("Verify existance of migration table '{}'", "KAR_migration");
if (da instanceof final DBAccessSQL daSQL) {
final boolean exist = da.isTableExist("KAR_migration");
if (!exist) {
LOGGER.info("'{}' Does not exist create a new one...", "KAR_migration");
// create the table:
List<String> sqlQuery;
try {
sqlQuery = DataFactory.createTable(Migration.class);
} catch (final Exception ex) {
ex.printStackTrace();
throw new MigrationException(
"Fail to create the local DB SQL model for migaration ==> wait administrator interventions");
}
LOGGER.info("Create Table with : {}", sqlQuery.get(0));
try {
daSQL.executeQuery(sqlQuery.get(0));
} catch (SQLException | IOException ex) {
ex.printStackTrace();
throw new MigrationException(
"Fail to create the local DB model for migaration ==> wait administrator interventions");
}
}
}
final Migration currentVersion = getCurrentVersion(da);
List<MigrationInterface> toApply = new ArrayList<>();
boolean needPlaceholder = false;
if (currentVersion == null) {
// This is a first migration
LOGGER.info("First installation of the system ==> Create the DB");
if (this.init == null) {
// No initialization class ==> manage a historical creation mode...
toApply = this.datas;
} else {
// Select Initialization class if it exist
toApply.add(this.init);
needPlaceholder = true;
}
} else {
if (!currentVersion.terminated) {
throw new MigrationException("An error occured in the last migration: '" + currentVersion.name
+ "' defect @" + currentVersion.stepId + "/" + currentVersion.count);
}
LOGGER.info("Upgrade the system Current version: {}", currentVersion.name);
boolean find = this.init != null && this.init.getName().equals(currentVersion.name);
if (find) {
toApply = this.datas;
} else {
LOGGER.info(" ===> Check what must be apply:");
for (final MigrationInterface elem : this.datas) {
LOGGER.info(" - {}", elem.getName());
if (!find) {
if (currentVersion.name.equals(elem.getName())) {
LOGGER.info(" == current version");
find = true;
}
continue;
}
LOGGER.info(" ++ add ");
toApply.add(elem);
}
}
}
final int id = 0;
final int count = toApply.size();
for (final MigrationInterface elem : toApply) {
migrateSingle(da, elem, id, count);
}
if (needPlaceholder) {
if (this.datas.size() == 0) {
// No placeholder needed, the model have no migration in the current version...
} else {
// we insert a placeholder to simulate the last migration is well done.
final String placeholderName = this.datas.get(this.datas.size() - 1).getName();
Migration migrationResult = new Migration();
migrationResult.id = 1000L;
migrationResult.name = placeholderName;
migrationResult.stepId = 0;
migrationResult.terminated = true;
migrationResult.count = 0;
migrationResult.log = "Place-holder for first initialization";
try {
migrationResult = da.insert(migrationResult);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
LOGGER.info("Execute migration ... [ END ]");
} catch (final InternalServerErrorException e) {
e.printStackTrace();
throw new MigrationException("TODO ...");
} catch (final IOException e) {
e.printStackTrace();
throw new MigrationException("TODO ...");
}
}
public void migrateSingle(final DBAccess da, final MigrationInterface elem, final int id, final int count)
throws MigrationException { throws MigrationException {
LOGGER.info("---------------------------------------------------------"); LOGGER.info("---------------------------------------------------------");
LOGGER.info("-- Migrate: [{}/{}] {} [BEGIN]", id, count, elem.getName()); LOGGER.info("-- Migrate: [{}/{}] {} [BEGIN]", id, count, elem.getName());
@ -274,7 +294,7 @@ public class MigrationEngine {
} }
migrationResult.log = log.toString(); migrationResult.log = log.toString();
try { try {
migrationResult = DataAccess.insert(migrationResult); migrationResult = da.insert(migrationResult);
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new MigrationException( throw new MigrationException(
@ -282,7 +302,7 @@ public class MigrationEngine {
} }
boolean ret = true; boolean ret = true;
try { try {
ret = elem.applyMigration(entry, log, migrationResult); ret = elem.applyMigration(da, log, migrationResult);
} catch (final Exception e) { } catch (final Exception e) {
log.append("\nFail in the migration apply "); log.append("\nFail in the migration apply ");
log.append(e.getLocalizedMessage()); log.append(e.getLocalizedMessage());
@ -293,7 +313,7 @@ public class MigrationEngine {
if (ret) { if (ret) {
migrationResult.terminated = true; migrationResult.terminated = true;
try { try {
DataAccess.update(migrationResult, migrationResult.id, List.of("terminated")); da.update(migrationResult, migrationResult.id, List.of("terminated"));
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new MigrationException( throw new MigrationException(
@ -303,7 +323,7 @@ public class MigrationEngine {
try { try {
log.append("Fail in the migration engine..."); log.append("Fail in the migration engine...");
migrationResult.log = log.toString(); migrationResult.log = log.toString();
DataAccess.update(migrationResult, migrationResult.id, List.of("log")); da.update(migrationResult, migrationResult.id, List.of("log"));
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new MigrationException("Fail to update migration Log in the migration table: " throw new MigrationException("Fail to update migration Log in the migration table: "
@ -316,8 +336,8 @@ public class MigrationEngine {
LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName()); LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName());
} }
public void revertTo(final DBEntry entry, final String migrationName) throws MigrationException { public void revertTo(final DBAccess da, final String migrationName) throws MigrationException {
final Migration currentVersion = getCurrentVersion(); final Migration currentVersion = getCurrentVersion(da);
final List<MigrationInterface> toApply = new ArrayList<>(); final List<MigrationInterface> toApply = new ArrayList<>();
boolean find = false; boolean find = false;
for (int iii = this.datas.size() - 1; iii >= 0; iii--) { for (int iii = this.datas.size() - 1; iii >= 0; iii--) {
@ -335,11 +355,11 @@ public class MigrationEngine {
final int id = 0; final int id = 0;
final int count = toApply.size(); final int count = toApply.size();
for (final MigrationInterface elem : toApply) { for (final MigrationInterface elem : toApply) {
revertSingle(entry, elem, id, count); revertSingle(da, elem, id, count);
} }
} }
public void revertSingle(final DBEntry entry, final MigrationInterface elem, final int id, final int count) { public void revertSingle(final DBAccess da, final MigrationInterface elem, final int id, final int count) {
LOGGER.info("Revert migration: {} [BEGIN]", elem.getName()); LOGGER.info("Revert migration: {} [BEGIN]", elem.getName());
LOGGER.info("Revert migration: {} [ END ]", elem.getName()); LOGGER.info("Revert migration: {} [ END ]", elem.getName());

View File

@ -1,6 +1,6 @@
package org.kar.archidata.migration; package org.kar.archidata.migration;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.migration.model.Migration; import org.kar.archidata.migration.model.Migration;
public interface MigrationInterface { public interface MigrationInterface {
@ -13,13 +13,13 @@ public interface MigrationInterface {
* @param log Stored data in the BDD for the migration progression. * @param log Stored data in the BDD for the migration progression.
* @param migration Migration post data on each step... * @param migration Migration post data on each step...
* @return true if migration is finished. */ * @return true if migration is finished. */
boolean applyMigration(DBEntry entry, StringBuilder log, Migration model) throws Exception; boolean applyMigration(DBAccess entry, StringBuilder log, Migration model) throws Exception;
/** Remove a migration the system to the previous version. /** Remove a migration the system to the previous version.
* @param entry DB interface for the migration. * @param entry DB interface for the migration.
* @param log Stored data in the BDD for the migration progression. * @param log Stored data in the BDD for the migration progression.
* @return true if migration is finished. */ * @return true if migration is finished. */
boolean revertMigration(DBEntry entry, StringBuilder log) throws Exception; boolean revertMigration(DBAccess entry, StringBuilder log) throws Exception;
/** Get the number of step in the migration process. /** Get the number of step in the migration process.
* @return count of SQL access. */ * @return count of SQL access. */

View File

@ -5,9 +5,9 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.migration.model.Migration; import org.kar.archidata.migration.model.Migration;
import org.kar.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -70,8 +70,7 @@ public class MigrationSqlStep implements MigrationInterface {
} }
@Override @Override
public boolean applyMigration(final DBEntry entry, final StringBuilder log, final Migration model) public boolean applyMigration(final DBAccess da, final StringBuilder log, final Migration model) throws Exception {
throws Exception {
if (!this.isGenerated) { if (!this.isGenerated) {
this.isGenerated = true; this.isGenerated = true;
generateStep(); generateStep();
@ -106,9 +105,11 @@ public class MigrationSqlStep implements MigrationInterface {
} }
try { try {
if (action.action() != null) { if (action.action() != null) {
DataAccess.executeQuery(action.action()); if (da instanceof final DBAccessSQL ioDBSQL) {
ioDBSQL.executeQuery(action.action());
}
} else { } else {
action.async().doRequest(); action.async().doRequest(da);
} }
} catch (SQLException | IOException ex) { } catch (SQLException | IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
@ -117,7 +118,7 @@ public class MigrationSqlStep implements MigrationInterface {
model.stepId = iii + 1; model.stepId = iii + 1;
model.log = log.toString(); model.log = log.toString();
try { try {
DataAccess.update(model, model.id, List.of("stepId", "log")); da.update(model, model.id, List.of("stepId", "log"));
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -128,7 +129,7 @@ public class MigrationSqlStep implements MigrationInterface {
model.stepId = iii + 1; model.stepId = iii + 1;
model.log = log.toString(); model.log = log.toString();
try { try {
DataAccess.update(model, model.id, List.of("stepId", "log")); da.update(model, model.id, List.of("stepId", "log"));
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -143,7 +144,7 @@ public class MigrationSqlStep implements MigrationInterface {
} }
@Override @Override
public boolean revertMigration(final DBEntry entry, final StringBuilder log) throws Exception { public boolean revertMigration(final DBAccess da, final StringBuilder log) throws Exception {
generateRevertStep(); generateRevertStep();
return false; return false;
} }

View File

@ -6,6 +6,7 @@ import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Table; import jakarta.persistence.Table;
@ -16,6 +17,7 @@ import jakarta.ws.rs.DefaultValue;
// TODO: Add a migration Hash to be sure that the current migration init is correct and has not change... // TODO: Add a migration Hash to be sure that the current migration init is correct and has not change...
@Table(name = "KAR_migration") @Table(name = "KAR_migration")
@Entity("KAR_migration")
@DataIfNotExists @DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class Migration extends GenericDataSoftDelete { public class Migration extends GenericDataSoftDelete {

View File

@ -11,7 +11,7 @@ import jakarta.persistence.Table;
@Table(name = "data") @Table(name = "data")
@DataIfNotExists @DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class Data extends UUIDGenericDataSoftDelete { public class Data extends OIDGenericDataSoftDelete {
@Column(length = 128, nullable = false) @Column(length = 128, nullable = false)
@Schema(description = "Sha512 of the data") @Schema(description = "Sha512 of the data")
public String sha512; public String sha512;

View File

@ -0,0 +1,17 @@
package org.kar.archidata.model;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Id;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
public class OIDGenericData extends GenericTiming {
@Id
@jakarta.persistence.Id
@Column(nullable = false, unique = true, name = "_id")
@Schema(description = "Unique ObjectID of the object", required = false, readOnly = true, example = "65161616841351")
@NotNull
public ObjectId oid = null;
}

View File

@ -0,0 +1,19 @@
package org.kar.archidata.model;
import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.ws.rs.DefaultValue;
public class OIDGenericDataSoftDelete extends OIDGenericData {
@DataNotRead
@Column(nullable = false)
@DefaultValue("'0'")
@DataDeleted
@Schema(description = "Deleted state", hidden = true, required = false, readOnly = true)
@Nullable
public Boolean deleted = null;
}

View File

@ -17,6 +17,7 @@ public class ConfigBaseVariable {
static public String eMailFrom; static public String eMailFrom;
static public String eMailLogin; static public String eMailLogin;
static public String eMailPassword; static public String eMailPassword;
static public Class<?>[] dbInterfacesClasses;
// For test only // For test only
public static void clearAllValue() { public static void clearAllValue() {
@ -36,6 +37,7 @@ public class ConfigBaseVariable {
eMailFrom = System.getenv("EMAIL_FROM"); eMailFrom = System.getenv("EMAIL_FROM");
eMailLogin = System.getenv("EMAIL_LOGIN"); eMailLogin = System.getenv("EMAIL_LOGIN");
eMailPassword = System.getenv("EMAIL_PASSWORD"); eMailPassword = System.getenv("EMAIL_PASSWORD");
dbInterfacesClasses = new Class<?>[0];
} }
static { static {
@ -70,11 +72,17 @@ public class ConfigBaseVariable {
return dbHost; return dbHost;
} }
public static String getDBPort() { public static Short getDBPort() {
if (dbPort == null) { if (dbPort == null) {
return "3306"; if (getDBType().equals("mongo")) {
return 27017;
}
return 3306;
} }
return dbPort; if (dbPort == null) {
return null;
}
return Short.parseShort(dbPort);
} }
public static String getDBLogin() { public static String getDBLogin() {
@ -139,4 +147,11 @@ public class ConfigBaseVariable {
return new EMailConfig(eMailFrom, eMailLogin, eMailPassword); return new EMailConfig(eMailFrom, eMailLogin, eMailPassword);
} }
public static Class<?>[] getBbInterfacesClasses() {
return dbInterfacesClasses;
}
public static void setBbInterfacesClasses(final Class<?>[] data) {
dbInterfacesClasses = data;
}
} }

View File

@ -0,0 +1,36 @@
package org.kar.archidata.tools;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.converter.jackson.JacksonModules;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class ContextGenericTools {
public static ObjectMapper createObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
// Configure Jackson for dates and times
objectMapper.registerModule(new JavaTimeModule()); // Module for Java 8+ Date and Time API
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// configure the local serialization modules
objectMapper.registerModule(JacksonModules.getAllModules());
return objectMapper;
}
/**
* Add support of Jackson jsr310 for data and time serialization and un-serialization.
* @param rc Resource exception model.
*/
public static void addJsr310(final ResourceConfig rc) {
final ObjectMapper objectMapper = createObjectMapper();
// configure jackson provider for JSON mapper
final JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(objectMapper);
// Record it on the Resource configuration
rc.register(provider);
}
}

View File

@ -13,15 +13,15 @@ import java.security.NoSuchAlgorithmException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID;
import org.apache.tika.Tika; import org.apache.tika.Tika;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.api.DataResource; import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.QueryAnd; import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson; import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.ReadAllColumn; import org.kar.archidata.dataAccess.options.ReadAllColumn;
import org.kar.archidata.exception.FailException; import org.kar.archidata.exception.FailException;
@ -77,9 +77,9 @@ public class DataTools {
return filePath; return filePath;
} }
public static Data getWithSha512(final String sha512) { public static Data getWithSha512(final DBAccess ioDb, final String sha512) {
try { try {
return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)), return ioDb.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)),
new ReadAllColumn()); new ReadAllColumn());
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
@ -88,9 +88,9 @@ public class DataTools {
return null; return null;
} }
public static Data getWithId(final long id) { public static Data getWithId(final DBAccess ioDb, final long id) {
try { try {
return DataAccess.getWhere(Data.class, new Condition(new QueryAnd( return ioDb.getWhere(Data.class, new Condition(new QueryAnd(
List.of(new QueryCondition("deleted", "=", false), new QueryCondition("id", "=", id))))); List.of(new QueryCondition("deleted", "=", false), new QueryCondition("id", "=", id)))));
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
@ -100,6 +100,7 @@ public class DataTools {
} }
public static Data createNewData( public static Data createNewData(
final DBAccess ioDb,
final long tmpUID, final long tmpUID,
final String originalFileName, final String originalFileName,
final String sha512, final String sha512,
@ -113,14 +114,14 @@ public class DataTools {
out.sha512 = sha512; out.sha512 = sha512;
out.mimeType = mimeType; out.mimeType = mimeType;
out.size = fileSize; out.size = fileSize;
out = DataAccess.insert(out); out = ioDb.insert(out);
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
final String mediaPath = DataResource.getFileData(out.uuid); final String mediaPath = DataResource.getFileData(out.oid);
LOGGER.info("src = {}", tmpPath); LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath); LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
@ -130,8 +131,11 @@ public class DataTools {
return out; return out;
} }
public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512) public static Data createNewData(
throws IOException, SQLException { final DBAccess ioDb,
final long tmpUID,
final String originalFileName,
final String sha512) throws IOException, SQLException {
// determine mime type: // determine mime type:
String mimeType = ""; String mimeType = "";
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
@ -144,12 +148,12 @@ public class DataTools {
case "webm" -> "video/webm"; case "webm" -> "video/webm";
default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'"); default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}; };
return createNewData(tmpUID, originalFileName, sha512, mimeType); return createNewData(ioDb, tmpUID, originalFileName, sha512, mimeType);
} }
public static void undelete(final UUID id) { public static void undelete(final DBAccess ioDb, final ObjectId oid) {
try { try {
DataAccess.unsetDelete(Data.class, id); ioDb.unsetDelete(Data.class, oid);
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -272,13 +276,14 @@ public class DataTools {
} }
public static <CLASS_TYPE, ID_TYPE> void uploadCoverFromUri( public static <CLASS_TYPE, ID_TYPE> void uploadCoverFromUri(
final DBAccess ioDb,
final Class<CLASS_TYPE> clazz, final Class<CLASS_TYPE> clazz,
final ID_TYPE id, final ID_TYPE id,
final String url) throws Exception { final String url) throws Exception {
LOGGER.info(" - id: {}", id); LOGGER.info(" - id: {}", id);
LOGGER.info(" - url: {} ", url); LOGGER.info(" - url: {} ", url);
final CLASS_TYPE media = DataAccess.get(clazz, id); final CLASS_TYPE media = ioDb.get(clazz, id);
if (media == null) { if (media == null) {
throw new InputException(clazz.getCanonicalName(), throw new InputException(clazz.getCanonicalName(),
"[" + id.toString() + "] Id does not exist or removed..."); "[" + id.toString() + "] Id does not exist or removed...");
@ -310,7 +315,7 @@ public class DataTools {
final long tmpUID = getTmpDataId(); final long tmpUID = getTmpDataId();
final String sha512 = saveTemporaryFile(dataResponse, tmpUID); final String sha512 = saveTemporaryFile(dataResponse, tmpUID);
Data data = getWithSha512(sha512); Data data = getWithSha512(ioDb, sha512);
final String mimeType = getMimeType(dataResponse); final String mimeType = getMimeType(dataResponse);
if (!Arrays.asList(SUPPORTED_IMAGE_MIME_TYPE).contains(mimeType)) { if (!Arrays.asList(SUPPORTED_IMAGE_MIME_TYPE).contains(mimeType)) {
throw new FailException(Response.Status.NOT_ACCEPTABLE, throw new FailException(Response.Status.NOT_ACCEPTABLE,
@ -321,7 +326,7 @@ public class DataTools {
if (data == null) { if (data == null) {
LOGGER.info("Need to add the data in the BDD ... "); LOGGER.info("Need to add the data in the BDD ... ");
try { try {
data = createNewData(tmpUID, url, sha512, mimeType); data = createNewData(ioDb, tmpUID, url, sha512, mimeType);
} catch (final IOException ex) { } catch (final IOException ex) {
removeTemporaryFile(tmpUID); removeTemporaryFile(tmpUID);
throw new FailException(Response.Status.NOT_MODIFIED, throw new FailException(Response.Status.NOT_MODIFIED,
@ -333,23 +338,18 @@ public class DataTools {
} }
} else if (data.deleted) { } else if (data.deleted) {
LOGGER.error("Data already exist but deleted"); LOGGER.error("Data already exist but deleted");
undelete(data.uuid); undelete(ioDb, data.oid);
data.deleted = false; data.deleted = false;
} else { } else {
LOGGER.error("Data already exist ... all good"); LOGGER.error("Data already exist ... all good");
} }
// Fist step: retrieve all the Id of each parents:... // Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode"); LOGGER.info("Find typeNode");
if (id instanceof final Long idLong) { AddOnDataJson.addLink(ioDb, clazz, null, id, null, data.oid);
AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid);
} else if (id instanceof final UUID idUUID) {
AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid);
} else {
throw new IOException("Fail to add Cover can not detect type...");
}
} }
public static <CLASS_TYPE, ID_TYPE> void uploadCover( public static <CLASS_TYPE, ID_TYPE> void uploadCover(
final DBAccess ioDb,
final Class<CLASS_TYPE> clazz, final Class<CLASS_TYPE> clazz,
final ID_TYPE id, final ID_TYPE id,
final InputStream fileInputStream, final InputStream fileInputStream,
@ -360,7 +360,7 @@ public class DataTools {
LOGGER.info(" - file_name: {} ", fileMetaData.getFileName()); LOGGER.info(" - file_name: {} ", fileMetaData.getFileName());
LOGGER.info(" - fileInputStream: {}", fileInputStream); LOGGER.info(" - fileInputStream: {}", fileInputStream);
LOGGER.info(" - fileMetaData: {}", fileMetaData); LOGGER.info(" - fileMetaData: {}", fileMetaData);
final CLASS_TYPE media = DataAccess.get(clazz, id); final CLASS_TYPE media = ioDb.get(clazz, id);
if (media == null) { if (media == null) {
throw new InputException(clazz.getCanonicalName(), throw new InputException(clazz.getCanonicalName(),
"[" + id.toString() + "] Id does not exist or removed..."); "[" + id.toString() + "] Id does not exist or removed...");
@ -368,11 +368,11 @@ public class DataTools {
final long tmpUID = getTmpDataId(); final long tmpUID = getTmpDataId();
final String sha512 = saveTemporaryFile(fileInputStream, tmpUID); final String sha512 = saveTemporaryFile(fileInputStream, tmpUID);
Data data = getWithSha512(sha512); Data data = getWithSha512(ioDb, sha512);
if (data == null) { if (data == null) {
LOGGER.info("Need to add the data in the BDD ... "); LOGGER.info("Need to add the data in the BDD ... ");
try { try {
data = createNewData(tmpUID, fileMetaData.getFileName(), sha512); data = createNewData(ioDb, tmpUID, fileMetaData.getFileName(), sha512);
} catch (final IOException ex) { } catch (final IOException ex) {
removeTemporaryFile(tmpUID); removeTemporaryFile(tmpUID);
throw new FailException(Response.Status.NOT_MODIFIED, throw new FailException(Response.Status.NOT_MODIFIED,
@ -384,19 +384,13 @@ public class DataTools {
} }
} else if (data.deleted) { } else if (data.deleted) {
LOGGER.error("Data already exist but deleted"); LOGGER.error("Data already exist but deleted");
undelete(data.uuid); undelete(ioDb, data.oid);
data.deleted = false; data.deleted = false;
} else { } else {
LOGGER.error("Data already exist ... all good"); LOGGER.error("Data already exist ... all good");
} }
// Fist step: retrieve all the Id of each parents:... // Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode"); LOGGER.info("Find typeNode");
if (id instanceof final Long idLong) { AddOnDataJson.addLink(ioDb, clazz, null, id, null, data.oid);
AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid);
} else if (id instanceof final UUID idUUID) {
AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid);
} else {
throw new IOException("Fail to add Cover can not detect type...");
}
} }
} }

View File

@ -108,7 +108,7 @@ public class JWTWrapper {
in.close(); in.close();
// print result // print result
LOGGER.debug(response.toString()); LOGGER.debug(response.toString());
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
final PublicKey values = mapper.readValue(response.toString(), PublicKey.class); final PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
rsaPublicJWK = RSAKey.parse(values.key); rsaPublicJWK = RSAKey.parse(values.key);
return; return;

View File

@ -25,10 +25,11 @@ public class RESTApi {
final static Logger LOGGER = LoggerFactory.getLogger(RESTApi.class); final static Logger LOGGER = LoggerFactory.getLogger(RESTApi.class);
final String baseUrl; final String baseUrl;
private String token = null; private String token = null;
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper;
public RESTApi(final String baseUrl) { public RESTApi(final String baseUrl) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.mapper = ContextGenericTools.createObjectMapper();
} }
public void setToken(final String token) { public void setToken(final String token) {

View File

@ -1,40 +1,157 @@
package test.kar.archidata; package test.kar.archidata;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.db.DBEntry; import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
import test.kar.archidata.dataAccess.model.SerializeAsJson;
import test.kar.archidata.dataAccess.model.SerializeListAsJson;
import test.kar.archidata.dataAccess.model.SimpleTable;
import test.kar.archidata.dataAccess.model.SimpleTableSoftDelete;
import test.kar.archidata.dataAccess.model.TypeManyToManyRemote;
import test.kar.archidata.dataAccess.model.TypeManyToManyRoot;
import test.kar.archidata.dataAccess.model.TypeManyToManyRootExpand;
import test.kar.archidata.dataAccess.model.TypeManyToOneRemote;
import test.kar.archidata.dataAccess.model.TypeManyToOneRoot;
import test.kar.archidata.dataAccess.model.TypeManyToOneRootExpand;
import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRemote;
import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRoot;
import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRootExpand;
import test.kar.archidata.dataAccess.model.TypeOneToManyRemote;
import test.kar.archidata.dataAccess.model.TypeOneToManyRoot;
import test.kar.archidata.dataAccess.model.TypeOneToManyRootExpand;
import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRemote;
import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRoot;
import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRootExpand;
import test.kar.archidata.dataAccess.model.TypesEnum1;
import test.kar.archidata.dataAccess.model.TypesEnum2;
import test.kar.archidata.dataAccess.model.TypesTable;
public class ConfigureDb { public class ConfigureDb {
final static private Logger LOGGER = LoggerFactory.getLogger(ConfigureDb.class); final static private Logger LOGGER = LoggerFactory.getLogger(ConfigureDb.class);
final static private String modeTestForced = null;// "MONGO";
public static DBAccess da = null;
public static void configure() throws IOException { public static void configure() throws IOException, InternalServerErrorException, DataAccessException {
if (true) { String modeTest = System.getenv("TEST_E2E_MODE");
if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) { if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite"; modeTest = "SQLITE-MEMORY";
ConfigBaseVariable.dbHost = "memory"; } else if ("true".equalsIgnoreCase(modeTest)) {
// for test we need to connect all time the DB modeTest = "MY-SQL";
ConfigBaseVariable.dbKeepConnected = "true"; }
} // override the local test:
} else { if (modeTestForced != null) {
// Enable this if you want to access to a local MySQL base to test with an adminer modeTest = modeTestForced;
}
final List<Class<?>> listObject = List.of( //
SerializeAsJson.class, //
SerializeListAsJson.class, //
SimpleTable.class, //
SimpleTableSoftDelete.class, //
TypeManyToManyRemote.class, //
TypeManyToManyRoot.class, //
TypeManyToManyRootExpand.class, //
TypeManyToOneRemote.class, //
TypeManyToOneRoot.class, //
TypeManyToOneRootExpand.class, //
TypeManyToOneUUIDRemote.class, //
TypeManyToOneUUIDRoot.class, //
TypeManyToOneUUIDRootExpand.class, //
TypeOneToManyRemote.class, //
TypeOneToManyRoot.class, //
TypeOneToManyRootExpand.class, //
TypeOneToManyUUIDRemote.class, //
TypeOneToManyUUIDRoot.class, //
TypeOneToManyUUIDRootExpand.class, //
TypesEnum1.class, //
TypesEnum2.class, //
TypesTable.class);
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mysql";
ConfigBaseVariable.bdDatabase = "test_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test_db";
} else {
// User local modification ...
ConfigBaseVariable.bdDatabase = "test_db"; ConfigBaseVariable.bdDatabase = "test_db";
ConfigBaseVariable.dbPort = "3906"; ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root"; ConfigBaseVariable.dbUser = "root";
//ConfigBaseVariable.dbPassword = "password";
} }
removeDB();
// Connect the dataBase... // Connect the dataBase...
final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); da = DBAccess.createInterface();
entry.connect(); }
public static void removeDB() {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
DbConfig config = null;
try {
config = new DbConfig();
} catch (final DataAccessException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
config.setDbName(null);
LOGGER.info("Remove the DB and create a new one '{}'", config.getDbName());
try (final DBAccess daRoot = DBAccess.createInterface(config)) {
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
// nothing to do ...
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
}
daRoot.createDB(ConfigBaseVariable.bdDatabase);
} catch (final InternalServerErrorException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
} catch (final IOException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
} }
public static void clear() throws IOException { public static void clear() throws IOException {
LOGGER.info("Remove the test db"); LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode(); removeDB();
// The connection is by default open ==> close it at the end of test:
da.close();
DbIoFactory.closeAllForceMode();
ConfigBaseVariable.clearAllValue(); ConfigBaseVariable.clearAllValue();
} }
} }

View File

@ -1,86 +0,0 @@
package test.kar.archidata;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.model.SerializeListAsJson;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestListJson {
final static private Logger LOGGER = LoggerFactory.getLogger(TestListJson.class);
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
}
@AfterAll
public static void removeDataBase() throws IOException {
ConfigureDb.clear();
}
@Order(1)
@Test
public void testTableInsertAndRetrieve() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJson.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuery(elem);
}
}
@Order(2)
@Test
public void testIO() throws Exception {
final SerializeListAsJson test = new SerializeListAsJson();
test.data = new ArrayList<>();
test.data.add(5);
test.data.add(2);
test.data.add(8);
test.data.add(6);
test.data.add(51);
final SerializeListAsJson insertedData = DataAccess.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(5, insertedData.data.size());
Assertions.assertEquals(test.data.get(0), insertedData.data.get(0));
Assertions.assertEquals(test.data.get(1), insertedData.data.get(1));
Assertions.assertEquals(test.data.get(2), insertedData.data.get(2));
Assertions.assertEquals(test.data.get(3), insertedData.data.get(3));
Assertions.assertEquals(test.data.get(4), insertedData.data.get(4));
// Try to retrieve all the data:
final SerializeListAsJson retrieve = DataAccess.get(SerializeListAsJson.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertTrue(retrieve.id >= 0);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(5, retrieve.data.size());
Assertions.assertEquals(test.data.get(0), retrieve.data.get(0));
Assertions.assertEquals(test.data.get(1), retrieve.data.get(1));
Assertions.assertEquals(test.data.get(2), retrieve.data.get(2));
Assertions.assertEquals(test.data.get(3), retrieve.data.get(3));
Assertions.assertEquals(test.data.get(4), retrieve.data.get(4));
}
}

View File

@ -1,108 +0,0 @@
package test.kar.archidata;
import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DataFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypesTable;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestRawQuery {
final static private Logger LOGGER = LoggerFactory.getLogger(TestTypes.class);
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
}
@AfterAll
public static void removeDataBase() throws IOException {
ConfigureDb.clear();
}
@Order(1)
@Test
public void testCreateTable() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(TypesTable.class);
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
DataAccess.executeSimpleQuery(elem);
}
}
@Order(2)
@Test
public void testGet() throws Exception {
final TypesTable test = new TypesTable();
test.intData = 95;
test.floatData = 1.0F;
DataAccess.insert(test);
test.intData = 96;
test.floatData = 2.0F;
DataAccess.insert(test);
test.intData = 97;
test.floatData = 3.0F;
DataAccess.insert(test);
test.intData = 98;
test.floatData = 4.0F;
DataAccess.insert(test);
test.intData = 99;
test.floatData = 5.0F;
DataAccess.insert(test);
test.intData = 99;
test.floatData = 6.0F;
DataAccess.insert(test);
test.intData = 99;
test.floatData = 7.0F;
DataAccess.insert(test);
{
final String query = """
SELECT *
FROM TypesTable
WHERE `intData` = ?
ORDER BY id DESC
""";
final List<Object> parameters = List.of(Integer.valueOf(99));
// Try to retrieve all the data:
final List<TypesTable> retrieve = DataAccess.query(TypesTable.class, query, parameters);
Assertions.assertNotNull(retrieve);
Assertions.assertEquals(3, retrieve.size());
Assertions.assertEquals(99, retrieve.get(0).intData);
Assertions.assertEquals(7.0F, retrieve.get(0).floatData);
Assertions.assertEquals(6.0F, retrieve.get(1).floatData);
Assertions.assertEquals(5.0F, retrieve.get(2).floatData);
}
{
final String query = """
SELECT DISTINCT intData
FROM TypesTable
WHERE `intData` = ?
ORDER BY id DESC
""";
final List<Object> parameters = List.of(Integer.valueOf(99));
// Try to retrieve all the data:
final List<TypesTable> retrieve = DataAccess.query(TypesTable.class, query, parameters);
Assertions.assertNotNull(retrieve);
Assertions.assertEquals(1, retrieve.size());
Assertions.assertEquals(99, retrieve.get(0).intData);
}
}
}

View File

@ -0,0 +1,34 @@
package test.kar.archidata.apiExtern;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.kar.archidata.tools.JWTWrapper;
public class Common {
public static final String USER_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_user_login", "KarAuth",
"farm.neo.back", //
Map.of("farm.neo.back", Map.of("USER", Boolean.TRUE)));
public static final String ADMIN_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_admin_login", "KarAuth",
"farm.neo.back", Map.of("farm.neo.back", Map.of("USER", Boolean.TRUE, "ADMIN", Boolean.TRUE)));
public static String RandGeneratedStr(final int length) {
final String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz0123456789éàê_- '()";
final StringBuilder out = new StringBuilder(length);
for (int iii = 0; iii < length; iii++) {
final int chId = (int) (base.length() * Math.random());
out.append(base.charAt(chId));
}
return out.toString();
}
public static void checkUUID(final UUID id) {
final String data = id.toString();
Assertions.assertFalse(data.equals("00000000-0000-0000-0000-000000000000"));
final String[] elems = data.split("-");
Assertions.assertEquals(elems.length, 5);
Assertions.assertTrue(elems[3].equals("0001"));
}
}

View File

@ -0,0 +1,96 @@
package test.kar.archidata.apiExtern;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.ConfigureDb;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.apiExtern.model.SimpleArchiveTable;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestAPI {
private final static Logger LOGGER = LoggerFactory.getLogger(TestAPI.class);
public final static String ENDPOINT_NAME = "TestResource";
static WebLauncherTest webInterface = null;
static RESTApi api = null;
private static Long idTest = 0L;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Clean previous table");
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
public static void stopWebServer() throws Exception {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
ConfigureDb.clear();
}
@Order(1)
@Test
public void insertValue() throws Exception {
final SimpleArchiveTable data = new SimpleArchiveTable();
data.name = "Test name";
final SimpleArchiveTable inserted = api.post(SimpleArchiveTable.class, TestAPI.ENDPOINT_NAME, data);
Assertions.assertNotNull(inserted);
Assertions.assertNotNull(inserted.id);
Assertions.assertNotNull(inserted.name);
Assertions.assertEquals(data.name, inserted.name);
TestAPI.idTest = inserted.id;
final SimpleArchiveTable retrieve = api.get(SimpleArchiveTable.class,
TestAPI.ENDPOINT_NAME + "/" + TestAPI.idTest);
Assertions.assertNotNull(retrieve);
Assertions.assertEquals(TestAPI.idTest, retrieve.id);
Assertions.assertNotNull(retrieve.name);
Assertions.assertEquals(data.name, retrieve.name);
}
@Order(2)
@Test
public void archiveValue() throws Exception {
final SimpleArchiveTable archivedData = api.archive(SimpleArchiveTable.class,
TestAPI.ENDPOINT_NAME + "/" + TestAPI.idTest);
Assertions.assertNotNull(archivedData);
Assertions.assertEquals(TestAPI.idTest, archivedData.id);
Assertions.assertNotNull(archivedData.name);
Assertions.assertNotNull(archivedData.archive);
}
@Order(2)
@Test
public void restoreValue() throws Exception {
final SimpleArchiveTable archivedData = api.restore(SimpleArchiveTable.class,
TestAPI.ENDPOINT_NAME + "/" + TestAPI.idTest);
Assertions.assertNotNull(archivedData);
Assertions.assertEquals(TestAPI.idTest, archivedData.id);
Assertions.assertNotNull(archivedData.name);
Assertions.assertNull(archivedData.archive);
}
}

View File

@ -0,0 +1,23 @@
package test.kar.archidata.apiExtern;
import org.kar.archidata.filter.AuthenticationFilter;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.Priority;
//@PreMatching
@Provider
@Priority(Priorities.AUTHENTICATION)
public class TestAuthenticationFilter extends AuthenticationFilter {
final Logger logger = LoggerFactory.getLogger(TestAuthenticationFilter.class);
public TestAuthenticationFilter() {
super("karusic");
}
}

View File

@ -0,0 +1,75 @@
package test.kar.archidata.apiExtern;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.ConfigureDb;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.apiExtern.model.DataForJSR310;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestTime {
private final static Logger LOGGER = LoggerFactory.getLogger(TestTime.class);
public final static String ENDPOINT_NAME = "TimeResource";
static WebLauncherTest webInterface = null;
static RESTApi api = null;
private static Long idTest = 0L;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Clean previous table");
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
public static void stopWebServer() throws Exception {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
ConfigureDb.clear();
}
@Order(1)
@Test
public void insertValue() throws Exception {
final DataForJSR310 data = new DataForJSR310();
data.time = LocalTime.now();
data.date = LocalDate.now();
data.dateTime = LocalDateTime.now();
final DataForJSR310 inserted = api.post(DataForJSR310.class, TestTime.ENDPOINT_NAME, data);
Assertions.assertNotNull(inserted);
Assertions.assertNotNull(inserted.time);
Assertions.assertNotNull(inserted.date);
Assertions.assertNotNull(inserted.dateTime);
Assertions.assertEquals(inserted.time, data.time);
Assertions.assertEquals(inserted.date, data.date);
Assertions.assertEquals(inserted.dateTime, data.dateTime);
}
}

View File

@ -0,0 +1,177 @@
package test.kar.archidata.apiExtern;
import java.net.URI;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource;
import org.kar.archidata.catcher.GenericCatcher;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.UriBuilder;
import test.kar.archidata.apiExtern.resource.TestResource;
import test.kar.archidata.apiExtern.resource.TimeResource;
public class WebLauncher {
final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
protected UpdateJwtPublicKey keyUpdater = null;
protected HttpServer server = null;
public WebLauncher() {}
private static URI getBaseURI() {
return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build();
}
public void migrateDB() throws Exception {
WebLauncher.LOGGER.info("Create migration engine");
final MigrationEngine migrationEngine = new MigrationEngine();
WebLauncher.LOGGER.info("Add initialization");
//migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
//migrationEngine.add(new Migration20231126());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
public static void main(final String[] args) throws Exception {
WebLauncher.LOGGER.info("[START] application wake UP");
final WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
launcher.process();
WebLauncher.LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
WebLauncher.LOGGER.info("STOP Key updater");
launcher.stopOther();
WebLauncher.LOGGER.info("STOP the REST server:");
}
public void plop(final String aaa) {
// List available Image Readers
WebLauncher.LOGGER.trace("Available Image Readers:");
final Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(aaa);
while (readers.hasNext()) {
final ImageReader reader = readers.next();
WebLauncher.LOGGER.trace("Reader: " + reader.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Reader CN: " + reader.getOriginatingProvider().getPluginClassName());
// ImageIO.deregisterServiceProvider(reader.getOriginatingProvider());
}
// List available Image Writers
WebLauncher.LOGGER.trace("\nAvailable Image Writers:");
final Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(aaa);
while (writers.hasNext()) {
final ImageWriter writer = writers.next();
WebLauncher.LOGGER.trace("Writer: " + writer.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Writer CN: " + writer.getOriginatingProvider().getPluginClassName());
}
}
public void process() throws InterruptedException, DataAccessException {
ImageIO.scanForPlugins();
plop("jpeg");
plop("png");
plop("webmp");
plop("webp");
// ===================================================================
// Configure resources
// ===================================================================
final ResourceConfig rc = new ResourceConfig();
// add multipart models ..
rc.register(MultiPartFeature.class);
// global authentication system
rc.register(OptionFilter.class);
// remove cors ==> all time called by an other system...
rc.register(CORSFilter.class);
// global authentication system
rc.register(TestAuthenticationFilter.class);
// register exception catcher
GenericCatcher.addAll(rc);
// add default resource:
rc.register(TestResource.class);
rc.register(TimeResource.class);
rc.register(DataResource.class);
rc.register(ProxyResource.class);
ContextGenericTools.addJsr310(rc);
// add jackson to be discover when we are ins standalone server
rc.register(JacksonFeature.class);
// enable this to show low level request
// rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
// System.out.println("Connect on the BDD:");
// System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'");
// System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'");
// System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
// System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
// System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
LOGGER.info(" ==> {}", new DbConfig());
LOGGER.info("OAuth service {}", getBaseURI());
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
final HttpServer serverLink = this.server;
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
LOGGER.warn("Stopping server..");
serverLink.shutdownNow();
}
}, "shutdownHook"));
// ===================================================================
// start periodic update of the token ...
// ===================================================================
this.keyUpdater = new UpdateJwtPublicKey();
this.keyUpdater.start();
// ===================================================================
// run JERSEY
// ===================================================================
try {
this.server.start();
LOGGER.info("Jersey app started at {}", getBaseURI());
} catch (final Exception e) {
LOGGER.error("There was an error while starting Grizzly HTTP server.");
e.printStackTrace();
}
}
public void stop() {
if (this.server != null) {
this.server.shutdownNow();
this.server = null;
}
}
public void stopOther() {
this.keyUpdater.kill();
try {
this.keyUpdater.join(4000, 0);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,19 @@
package test.kar.archidata.apiExtern;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherTest extends WebLauncher {
final private static Logger LOGGER = LoggerFactory.getLogger(WebLauncherTest.class);
public WebLauncherTest() {
LOGGER.debug("Configure REST system");
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/";
// Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true";
// ConfigBaseVariable.dbPort = "3306";
}
}

View File

@ -0,0 +1,17 @@
package test.kar.archidata.apiExtern.model;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class DataForJSR310 {
public LocalTime time;
public LocalDate date;
public LocalDateTime dateTime;
@Override
public String toString() {
return "DataForJSR310 [time=" + this.time + ", date=" + this.date + ", dateTime=" + this.dateTime + "]";
}
}

View File

@ -0,0 +1,17 @@
package test.kar.archidata.apiExtern.model;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
public class DataTimes {
public Date time;
public Timestamp date;
public LocalDateTime dateTime;
@Override
public String toString() {
return "DataForJSR310 [time=" + this.time + ", date=" + this.date + ", dateTime=" + this.dateTime + "]";
}
}

View File

@ -0,0 +1,14 @@
package test.kar.archidata.apiExtern.model;
import java.util.Date;
import org.kar.archidata.model.GenericData;
import com.fasterxml.jackson.annotation.JsonFormat;
public class SimpleArchiveTable extends GenericData {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
public Date archive;
public String name;
}

View File

@ -0,0 +1,125 @@
package test.kar.archidata.apiExtern.resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.kar.archidata.annotation.ARCHIVE;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.RESTORE;
import org.kar.archidata.exception.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import test.kar.archidata.apiExtern.model.SimpleArchiveTable;
@Path("/TestResource")
@Produces({ MediaType.APPLICATION_JSON })
public class TestResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TestResource.class);
private static final List<SimpleArchiveTable> data = new ArrayList<>();
private static long uniqueId = 330;
@GET
@PermitAll
public List<SimpleArchiveTable> gets() throws Exception {
return TestResource.data;
}
@GET
@Path("{id}")
@PermitAll
public SimpleArchiveTable get(@PathParam("id") final Long id) throws Exception {
LOGGER.info("get({})", id);
for (final SimpleArchiveTable elem : TestResource.data) {
if (elem.id.equals(id)) {
return elem;
}
}
throw new NotFoundException("element does not exist: " + id);
}
@ARCHIVE
@Path("{id}")
@PermitAll
public SimpleArchiveTable archive(@PathParam("id") final Long id) throws Exception {
LOGGER.info("archive({})", id);
for (final SimpleArchiveTable elem : TestResource.data) {
if (elem.id.equals(id)) {
elem.updatedAt = new Date();
elem.archive = new Date();
return elem;
}
}
throw new NotFoundException("element does not exist: " + id);
}
@RESTORE
@Path("{id}")
@PermitAll
public SimpleArchiveTable restore(@PathParam("id") final Long id) throws Exception {
LOGGER.info("restore({})", id);
for (final SimpleArchiveTable elem : TestResource.data) {
if (elem.id.equals(id)) {
elem.updatedAt = new Date();
elem.archive = null;
return elem;
}
}
throw new NotFoundException("element does not exist: " + id);
}
@POST
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public SimpleArchiveTable post(final SimpleArchiveTable data) throws Exception {
LOGGER.info("post(...)");
data.id = TestResource.uniqueId;
TestResource.uniqueId += 5;
data.updatedAt = new Date();
data.createdAt = new Date();
this.data.add(data);
return data;
}
@PATCH
@Path("{id}")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public SimpleArchiveTable patch(
@PathParam("id") final Long id,
@AsyncType(SimpleArchiveTable.class) final String jsonRequest) throws Exception {
LOGGER.info("patch({})", id);
throw new NotFoundException("element does not exist: " + id);
}
@PUT
@Path("{id}")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public SimpleArchiveTable put(@PathParam("id") final Long id, final SimpleArchiveTable data) throws Exception {
LOGGER.info("put({})", id);
throw new NotFoundException("element does not exist: " + id);
}
@DELETE
@Path("{id}")
@PermitAll
public void remove(@PathParam("id") final Long id) throws Exception {
LOGGER.info("remove({})", id);
TestResource.data.removeIf(e -> e.id.equals(id));
}
}

View File

@ -0,0 +1,91 @@
package test.kar.archidata.apiExtern.resource;
import java.util.List;
import org.kar.archidata.annotation.ARCHIVE;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.RESTORE;
import org.kar.archidata.dataAccess.DataAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import test.kar.archidata.dataAccess.model.SimpleTable;
@Path("/TestResourceSample")
@Produces({ MediaType.APPLICATION_JSON })
public class TestResourceSample {
private static final Logger LOGGER = LoggerFactory.getLogger(TestResource.class);
@GET
@PermitAll
public List<SimpleTable> gets() throws Exception {
return DataAccess.gets(SimpleTable.class);
}
@GET
@Path("{id}")
@PermitAll
public SimpleTable get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(SimpleTable.class, id);
}
@ARCHIVE
@Path("{id}")
@PermitAll
public SimpleTable archive(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(SimpleTable.class, id);
}
@RESTORE
@Path("{id}")
@PermitAll
public SimpleTable restore(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(SimpleTable.class, id);
}
@POST
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public SimpleTable post(final SimpleTable data) throws Exception {
return DataAccess.insert(data);
}
@PATCH
@Path("{id}")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public SimpleTable patch(@PathParam("id") final Long id, @AsyncType(SimpleTable.class) final String jsonRequest)
throws Exception {
DataAccess.updateWithJson(SimpleTable.class, id, jsonRequest);
return DataAccess.get(SimpleTable.class, id);
}
@PUT
@Path("{id}")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public SimpleTable put(@PathParam("id") final Long id, final SimpleTable data) throws Exception {
DataAccess.update(data, id);
return DataAccess.get(SimpleTable.class, id);
}
@DELETE
@Path("{id}")
@PermitAll
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(SimpleTable.class, id);
}
}

View File

@ -0,0 +1,25 @@
package test.kar.archidata.apiExtern.resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import test.kar.archidata.apiExtern.model.DataForJSR310;
@Path("/TimeResource")
@Produces({ MediaType.APPLICATION_JSON })
public class TimeResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TimeResource.class);
@POST
@PermitAll
public DataForJSR310 post(final DataForJSR310 data) throws Exception {
LOGGER.warn("receive Data: {}", data);
return data;
}
}

View File

@ -0,0 +1,44 @@
package test.kar.archidata.dataAccess;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.exception.InputException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.dataAccess.model.DataInJson;
import test.kar.archidata.dataAccess.model.DataWithSubJson;
import test.kar.archidata.dataAccess.model.DataWithSubJson.DataWithSubJsonChecker;
@ExtendWith(StepwiseExtension.class)
public class TestDataJson {
final static private Logger LOGGER = LoggerFactory.getLogger(TestDataJson.class);
@Test
public void testCheckerDoesNotThrow() throws Exception {
final DataWithSubJson data = new DataWithSubJson();
data.dataSerialized = new DataInJson();
data.dataSerialized.data = "65454";
final DataWithSubJsonChecker checker = new DataWithSubJsonChecker();
Assertions.assertDoesNotThrow(() -> {
checker.check(null, "", data);
});
}
@Test
public void testCheckerDoesThrow() throws Exception {
final DataWithSubJson data = new DataWithSubJson();
data.dataSerialized = new DataInJson();
data.dataSerialized.data = "lqksjdflkjqsdf";
final DataWithSubJsonChecker checker = new DataWithSubJsonChecker();
final InputException res = Assertions.assertThrows(InputException.class, () -> {
checker.check(null, "", data);
});
Assertions.assertEquals(res.getMessage(),
"does not match the required pattern (constraints) must be '^[0-9]+$'");
}
}

View File

@ -0,0 +1,69 @@
package test.kar.archidata.dataAccess;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.dataAccess.model.DataInJson;
import test.kar.archidata.dataAccess.model.DataInJson.DataInJsonChecker;
@ExtendWith(StepwiseExtension.class)
public class TestJPAChecker {
final static private Logger LOGGER = LoggerFactory.getLogger(TestJPAChecker.class);
class DataInJsonCheckerTest extends DataInJsonChecker {
public void testWithCorrectFieldName() throws Exception {
initialize();
add("data",
(
final DBAccess ioDb,
final String baseName,
final DataInJson data,
final List<String> modifiedValue,
final QueryOptions options) -> {
// nothing to do...
});
}
public void testWithWrongFieldName() throws Exception {
initialize();
add("dqsdfqsdfqsdfqsdfata",
(
final DBAccess ioDb,
final String baseName,
final DataInJson data,
final List<String> modifiedValue,
final QueryOptions options) -> {
// nothing to do...
});
}
}
@Test
public void testThrowWhenFieldDoesNotExist() throws Exception {
final DataInJsonCheckerTest checker = new DataInJsonCheckerTest();
final DataAccessException res = Assertions.assertThrows(DataAccessException.class, () -> {
checker.testWithWrongFieldName();
});
Assertions.assertEquals(res.getMessage(),
"Try to add a JPA Filter on an inexistant Field: 'dqsdfqsdfqsdfqsdfata' not in [data]");
}
@Test
public void testThrowWhenFieldThatExist() throws Exception {
final DataInJsonCheckerTest checker = new DataInJsonCheckerTest();
Assertions.assertDoesNotThrow(() -> {
checker.testWithCorrectFieldName();
});
}
}

View File

@ -1,4 +1,4 @@
package test.kar.archidata; package test.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -11,13 +11,15 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import test.kar.archidata.model.SerializeAsJson; import test.kar.archidata.ConfigureDb;
import test.kar.archidata.model.SimpleTable; import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.dataAccess.model.SerializeAsJson;
import test.kar.archidata.dataAccess.model.SimpleTable;
@ExtendWith(StepwiseExtension.class) @ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -36,11 +38,13 @@ public class TestJson {
@Order(1) @Order(1)
@Test @Test
public void testTableInsertAndRetrieve() throws Exception { public void testTableFactory() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(SerializeAsJson.class); final List<String> sqlCommand = DataFactory.createTable(SerializeAsJson.class);
for (final String elem : sqlCommand) { if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
LOGGER.debug("request: '{}'", elem); for (final String elem : sqlCommand) {
DataAccess.executeSimpleQuery(elem); LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
} }
} }
@ -51,7 +55,7 @@ public class TestJson {
test.data = new SimpleTable(); test.data = new SimpleTable();
test.data.data = "plopppopql"; test.data.data = "plopppopql";
final SerializeAsJson insertedData = DataAccess.insert(test); final SerializeAsJson insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id); Assertions.assertNotNull(insertedData.id);
@ -61,7 +65,7 @@ public class TestJson {
Assertions.assertEquals(test.data.data, insertedData.data.data); Assertions.assertEquals(test.data.data, insertedData.data.data);
// Try to retrieve all the data: // Try to retrieve all the data:
final SerializeAsJson retrieve = DataAccess.get(SerializeAsJson.class, insertedData.id); final SerializeAsJson retrieve = ConfigureDb.da.get(SerializeAsJson.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);

View File

@ -0,0 +1,240 @@
package test.kar.archidata.dataAccess;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.ConfigureDb;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.dataAccess.model.SerializeListAsJson;
import test.kar.archidata.dataAccess.model.SerializeListAsJsonObjectId;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestListJson {
final static private Logger LOGGER = LoggerFactory.getLogger(TestListJson.class);
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
}
@AfterAll
public static void removeDataBase() throws IOException {
ConfigureDb.clear();
}
@Order(1)
@Test
public void testTableInsertAndRetrieve() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJson.class);
if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
}
}
@Order(2)
@Test
public void testIO() throws Exception {
final SerializeListAsJson test = new SerializeListAsJson();
test.data = new ArrayList<>();
test.data.add(5);
test.data.add(2);
test.data.add(8);
test.data.add(6);
test.data.add(51);
final SerializeListAsJson insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(5, insertedData.data.size());
Assertions.assertEquals(test.data.get(0), insertedData.data.get(0));
Assertions.assertEquals(test.data.get(1), insertedData.data.get(1));
Assertions.assertEquals(test.data.get(2), insertedData.data.get(2));
Assertions.assertEquals(test.data.get(3), insertedData.data.get(3));
Assertions.assertEquals(test.data.get(4), insertedData.data.get(4));
// Try to retrieve all the data:
final SerializeListAsJson retrieve = ConfigureDb.da.get(SerializeListAsJson.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertTrue(retrieve.id >= 0);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(5, retrieve.data.size());
Assertions.assertEquals(test.data.get(0), retrieve.data.get(0));
Assertions.assertEquals(test.data.get(1), retrieve.data.get(1));
Assertions.assertEquals(test.data.get(2), retrieve.data.get(2));
Assertions.assertEquals(test.data.get(3), retrieve.data.get(3));
Assertions.assertEquals(test.data.get(4), retrieve.data.get(4));
}
@Order(3)
@Test
public void testToolInsert() throws Exception {
final SerializeListAsJson test = new SerializeListAsJson();
test.data = new ArrayList<>();
final SerializeListAsJson insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(0, insertedData.data.size());
final Integer firstDataInserted1 = 111;
final Integer firstDataInserted2 = 222;
final Integer firstDataInserted3 = 333;
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJson.class, null, insertedData.id, "data",
firstDataInserted1);
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJson.class, null, insertedData.id, "data",
firstDataInserted2);
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJson.class, null, insertedData.id, "data",
firstDataInserted3);
// Try to retrieve all the data:
SerializeListAsJson retrieve = ConfigureDb.da.get(SerializeListAsJson.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertTrue(retrieve.id >= 0);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(3, retrieve.data.size());
Assertions.assertEquals(firstDataInserted1, retrieve.data.get(0));
Assertions.assertEquals(firstDataInserted2, retrieve.data.get(1));
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(2));
AddOnDataJson.removeLink(ConfigureDb.da, SerializeListAsJson.class, null, insertedData.id, "data",
firstDataInserted2);
// Try to retrieve all the data:
retrieve = ConfigureDb.da.get(SerializeListAsJson.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertTrue(retrieve.id >= 0);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(2, retrieve.data.size());
Assertions.assertEquals(firstDataInserted1, retrieve.data.get(0));
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(1));
}
@Order(101)
@Test
public void testOIDTableInsertAndRetrieve() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJsonObjectId.class);
if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
}
}
@Order(102)
@Test
public void testOIDIO() throws Exception {
final SerializeListAsJsonObjectId test = new SerializeListAsJsonObjectId();
test.data = new ArrayList<>();
test.data.add(new ObjectId());
test.data.add(new ObjectId());
test.data.add(new ObjectId());
test.data.add(new ObjectId());
test.data.add(new ObjectId());
final SerializeListAsJsonObjectId insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.oid);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(5, insertedData.data.size());
Assertions.assertEquals(test.data.get(0), insertedData.data.get(0));
Assertions.assertEquals(test.data.get(1), insertedData.data.get(1));
Assertions.assertEquals(test.data.get(2), insertedData.data.get(2));
Assertions.assertEquals(test.data.get(3), insertedData.data.get(3));
Assertions.assertEquals(test.data.get(4), insertedData.data.get(4));
// Try to retrieve all the data:
final SerializeListAsJsonObjectId retrieve = ConfigureDb.da.get(SerializeListAsJsonObjectId.class,
insertedData.oid);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.oid);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(5, retrieve.data.size());
Assertions.assertEquals(test.data.get(0), retrieve.data.get(0));
Assertions.assertEquals(test.data.get(1), retrieve.data.get(1));
Assertions.assertEquals(test.data.get(2), retrieve.data.get(2));
Assertions.assertEquals(test.data.get(3), retrieve.data.get(3));
Assertions.assertEquals(test.data.get(4), retrieve.data.get(4));
}
@Order(103)
@Test
public void testOIDToolInsert() throws Exception {
final SerializeListAsJsonObjectId test = new SerializeListAsJsonObjectId();
test.data = new ArrayList<>();
final SerializeListAsJsonObjectId insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.oid);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(0, insertedData.data.size());
final ObjectId firstDataInserted1 = new ObjectId();
final ObjectId firstDataInserted2 = new ObjectId();
final ObjectId firstDataInserted3 = new ObjectId();
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData.oid, "data",
firstDataInserted1);
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData.oid, "data",
firstDataInserted2);
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData.oid, "data",
firstDataInserted3);
// Try to retrieve all the data:
SerializeListAsJsonObjectId retrieve = ConfigureDb.da.get(SerializeListAsJsonObjectId.class, insertedData.oid);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.oid);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(3, retrieve.data.size());
Assertions.assertEquals(firstDataInserted1, retrieve.data.get(0));
Assertions.assertEquals(firstDataInserted2, retrieve.data.get(1));
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(2));
AddOnDataJson.removeLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData.oid, "data",
firstDataInserted2);
// Try to retrieve all the data:
retrieve = ConfigureDb.da.get(SerializeListAsJsonObjectId.class, insertedData.oid);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.oid);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(2, retrieve.data.size());
Assertions.assertEquals(firstDataInserted1, retrieve.data.get(0));
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(1));
}
}

View File

@ -1,4 +1,4 @@
package test.kar.archidata; package test.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -11,15 +11,17 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypeManyToManyRemote; import test.kar.archidata.ConfigureDb;
import test.kar.archidata.model.TypeManyToManyRoot; import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.model.TypeManyToManyRootExpand; import test.kar.archidata.dataAccess.model.TypeManyToManyRemote;
import test.kar.archidata.dataAccess.model.TypeManyToManyRoot;
import test.kar.archidata.dataAccess.model.TypeManyToManyRootExpand;
@ExtendWith(StepwiseExtension.class) @ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -42,9 +44,11 @@ public class TestManyToMany {
final List<String> sqlCommand2 = DataFactory.createTable(TypeManyToManyRoot.class); final List<String> sqlCommand2 = DataFactory.createTable(TypeManyToManyRoot.class);
final List<String> sqlCommand = DataFactory.createTable(TypeManyToManyRemote.class); final List<String> sqlCommand = DataFactory.createTable(TypeManyToManyRemote.class);
sqlCommand.addAll(sqlCommand2); sqlCommand.addAll(sqlCommand2);
for (final String elem : sqlCommand) { if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
LOGGER.debug("request: '{}'", elem); for (final String elem : sqlCommand) {
DataAccess.executeSimpleQuery(elem); LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
} }
} }
@ -53,14 +57,14 @@ public class TestManyToMany {
public void testSimpleInsertAndRetieve() throws Exception { public void testSimpleInsertAndRetieve() throws Exception {
final TypeManyToManyRoot test = new TypeManyToManyRoot(); final TypeManyToManyRoot test = new TypeManyToManyRoot();
test.otherData = "kjhlkjlkj"; test.otherData = "kjhlkjlkj";
final TypeManyToManyRoot insertedData = DataAccess.insert(test); final TypeManyToManyRoot insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id); Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0); Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertNull(insertedData.remote); Assertions.assertNull(insertedData.remote);
// Try to retrieve all the data: // Try to retrieve all the data:
final TypeManyToManyRoot retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); final TypeManyToManyRoot retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
@ -69,7 +73,7 @@ public class TestManyToMany {
Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertNull(retrieve.remote); Assertions.assertNull(retrieve.remote);
DataAccess.delete(TypeManyToManyRoot.class, insertedData.id); ConfigureDb.da.delete(TypeManyToManyRoot.class, insertedData.id);
} }
@Order(3) @Order(3)
@ -78,24 +82,24 @@ public class TestManyToMany {
TypeManyToManyRemote remote = new TypeManyToManyRemote(); TypeManyToManyRemote remote = new TypeManyToManyRemote();
remote.data = "remote1"; remote.data = "remote1";
final TypeManyToManyRemote insertedRemote1 = DataAccess.insert(remote); final TypeManyToManyRemote insertedRemote1 = ConfigureDb.da.insert(remote);
Assertions.assertEquals(insertedRemote1.data, remote.data); Assertions.assertEquals(insertedRemote1.data, remote.data);
remote = new TypeManyToManyRemote(); remote = new TypeManyToManyRemote();
remote.data = "remote2"; remote.data = "remote2";
final TypeManyToManyRemote insertedRemote2 = DataAccess.insert(remote); final TypeManyToManyRemote insertedRemote2 = ConfigureDb.da.insert(remote);
Assertions.assertEquals(insertedRemote2.data, remote.data); Assertions.assertEquals(insertedRemote2.data, remote.data);
final TypeManyToManyRoot test = new TypeManyToManyRoot(); final TypeManyToManyRoot test = new TypeManyToManyRoot();
test.otherData = "kjhlkjlkj"; test.otherData = "kjhlkjlkj";
final TypeManyToManyRoot insertedData = DataAccess.insert(test); final TypeManyToManyRoot insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id); Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0); Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertNull(insertedData.remote); Assertions.assertNull(insertedData.remote);
// Try to retrieve all the data: // Try to retrieve all the data:
TypeManyToManyRoot retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); TypeManyToManyRoot retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
@ -105,10 +109,10 @@ public class TestManyToMany {
Assertions.assertNull(retrieve.remote); Assertions.assertNull(retrieve.remote);
// Add remote elements // Add remote elements
AddOnManyToMany.addLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); AddOnManyToMany.addLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id);
AddOnManyToMany.addLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); AddOnManyToMany.addLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id);
retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
@ -120,7 +124,8 @@ public class TestManyToMany {
Assertions.assertEquals(retrieve.remote.get(0), insertedRemote1.id); Assertions.assertEquals(retrieve.remote.get(0), insertedRemote1.id);
Assertions.assertEquals(retrieve.remote.get(1), insertedRemote2.id); Assertions.assertEquals(retrieve.remote.get(1), insertedRemote2.id);
final TypeManyToManyRootExpand retrieveExpand = DataAccess.get(TypeManyToManyRootExpand.class, insertedData.id); final TypeManyToManyRootExpand retrieveExpand = ConfigureDb.da.get(TypeManyToManyRootExpand.class,
insertedData.id);
Assertions.assertNotNull(retrieveExpand); Assertions.assertNotNull(retrieveExpand);
Assertions.assertNotNull(retrieveExpand.id); Assertions.assertNotNull(retrieveExpand.id);
@ -133,10 +138,11 @@ public class TestManyToMany {
Assertions.assertEquals(retrieveExpand.remote.get(1).id, insertedRemote2.id); Assertions.assertEquals(retrieveExpand.remote.get(1).id, insertedRemote2.id);
// Remove an element // Remove an element
int count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); long count = AddOnManyToMany.removeLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote",
insertedRemote1.id);
Assertions.assertEquals(1, count); Assertions.assertEquals(1, count);
retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
@ -148,10 +154,11 @@ public class TestManyToMany {
Assertions.assertEquals(retrieve.remote.get(0), insertedRemote2.id); Assertions.assertEquals(retrieve.remote.get(0), insertedRemote2.id);
// Remove the second element // Remove the second element
count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); count = AddOnManyToMany.removeLink(ConfigureDb.da, TypeManyToManyRoot.class, retrieve.id, "remote",
insertedRemote2.id);
Assertions.assertEquals(1, count); Assertions.assertEquals(1, count);
retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); retrieve = ConfigureDb.da.get(TypeManyToManyRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
@ -160,9 +167,9 @@ public class TestManyToMany {
Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertNull(retrieve.remote); Assertions.assertNull(retrieve.remote);
DataAccess.delete(TypeManyToManyRoot.class, insertedData.id); ConfigureDb.da.delete(TypeManyToManyRoot.class, insertedData.id);
} }
/* API TODO: - Replace list (permet de les ordonnées) - remove all links - delete en cascade .... (compliqué...) */ /* API TODO: - Replace list (permet de les ordonnées) - remove all links - delete en cascade .... (compliqué...) */
} }

View File

@ -1,4 +1,4 @@
package test.kar.archidata; package test.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -11,17 +11,19 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypeManyToOneRemote; import test.kar.archidata.ConfigureDb;
import test.kar.archidata.model.TypeManyToOneRoot; import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.model.TypeManyToOneRootExpand; import test.kar.archidata.dataAccess.model.TypeManyToOneRemote;
import test.kar.archidata.model.TypeManyToOneUUIDRemote; import test.kar.archidata.dataAccess.model.TypeManyToOneRoot;
import test.kar.archidata.model.TypeManyToOneUUIDRoot; import test.kar.archidata.dataAccess.model.TypeManyToOneRootExpand;
import test.kar.archidata.model.TypeManyToOneUUIDRootExpand; import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRemote;
import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRoot;
import test.kar.archidata.dataAccess.model.TypeManyToOneUUIDRootExpand;
@ExtendWith(StepwiseExtension.class) @ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -45,9 +47,11 @@ public class TestManyToOne {
sqlCommand.addAll(DataFactory.createTable(TypeManyToOneRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeManyToOneRoot.class));
sqlCommand.addAll(DataFactory.createTable(TypeManyToOneUUIDRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeManyToOneUUIDRoot.class));
sqlCommand.addAll(DataFactory.createTable(TypeManyToOneUUIDRemote.class)); sqlCommand.addAll(DataFactory.createTable(TypeManyToOneUUIDRemote.class));
for (final String elem : sqlCommand) { if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
LOGGER.debug("request: '{}'", elem); for (final String elem : sqlCommand) {
DataAccess.executeSimpleQuery(elem); LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
} }
} }
@ -56,32 +60,32 @@ public class TestManyToOne {
public void testRemoteLong() throws Exception { public void testRemoteLong() throws Exception {
TypeManyToOneRemote remote = new TypeManyToOneRemote(); TypeManyToOneRemote remote = new TypeManyToOneRemote();
remote.data = "remote1"; remote.data = "remote1";
final TypeManyToOneRemote insertedRemote1 = DataAccess.insert(remote); final TypeManyToOneRemote insertedRemote1 = ConfigureDb.da.insert(remote);
Assertions.assertEquals(insertedRemote1.data, remote.data); Assertions.assertEquals(insertedRemote1.data, remote.data);
remote = new TypeManyToOneRemote(); remote = new TypeManyToOneRemote();
remote.data = "remote2"; remote.data = "remote2";
final TypeManyToOneRemote insertedRemote2 = DataAccess.insert(remote); final TypeManyToOneRemote insertedRemote2 = ConfigureDb.da.insert(remote);
Assertions.assertEquals(insertedRemote2.data, remote.data); Assertions.assertEquals(insertedRemote2.data, remote.data);
final TypeManyToOneRoot test = new TypeManyToOneRoot(); final TypeManyToOneRoot test = new TypeManyToOneRoot();
test.otherData = "kjhlkjlkj"; test.otherData = "kjhlkjlkj";
test.remoteId = insertedRemote2.id; test.remoteId = insertedRemote2.id;
final TypeManyToOneRoot insertedData = DataAccess.insert(test); final TypeManyToOneRoot insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id); Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0); Assertions.assertTrue(insertedData.id >= 0);
Assertions.assertEquals(test.otherData, insertedData.otherData); Assertions.assertEquals(test.otherData, insertedData.otherData);
Assertions.assertEquals(insertedRemote2.id, insertedData.remoteId); Assertions.assertEquals(insertedRemote2.id, insertedData.remoteId);
TypeManyToOneRoot retrieve = DataAccess.get(TypeManyToOneRoot.class, insertedData.id); TypeManyToOneRoot retrieve = ConfigureDb.da.get(TypeManyToOneRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId); Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId);
TypeManyToOneRootExpand retrieve2 = DataAccess.get(TypeManyToOneRootExpand.class, insertedData.id); TypeManyToOneRootExpand retrieve2 = ConfigureDb.da.get(TypeManyToOneRootExpand.class, insertedData.id);
Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.id); Assertions.assertNotNull(retrieve2.id);
Assertions.assertEquals(insertedData.id, retrieve2.id); Assertions.assertEquals(insertedData.id, retrieve2.id);
@ -91,19 +95,22 @@ public class TestManyToOne {
Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data); Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data);
// remove values: // remove values:
final int count = DataAccess.delete(TypeManyToOneRemote.class, remote.id); try {
Assertions.assertEquals(1, count); final long count = ConfigureDb.da.delete(TypeManyToOneRemote.class, insertedRemote2.id);
Assertions.assertEquals(1L, count);
} catch (final Exception ex) {
ex.printStackTrace();
}
// check fail: // check fail:
retrieve = DataAccess.get(TypeManyToOneRoot.class, insertedData.id); retrieve = ConfigureDb.da.get(TypeManyToOneRoot.class, insertedData.id);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id); Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId); Assertions.assertEquals(insertedRemote2.id, retrieve.remoteId);
retrieve2 = DataAccess.get(TypeManyToOneRootExpand.class, insertedData.id); retrieve2 = ConfigureDb.da.get(TypeManyToOneRootExpand.class, insertedData.id);
Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.id); Assertions.assertNotNull(retrieve2.id);
Assertions.assertEquals(insertedData.id, retrieve2.id); Assertions.assertEquals(insertedData.id, retrieve2.id);
@ -116,31 +123,32 @@ public class TestManyToOne {
public void testRemoteUUID() throws Exception { public void testRemoteUUID() throws Exception {
TypeManyToOneUUIDRemote remote = new TypeManyToOneUUIDRemote(); TypeManyToOneUUIDRemote remote = new TypeManyToOneUUIDRemote();
remote.data = "remote1"; remote.data = "remote1";
final TypeManyToOneUUIDRemote insertedRemote1 = DataAccess.insert(remote); final TypeManyToOneUUIDRemote insertedRemote1 = ConfigureDb.da.insert(remote);
Assertions.assertEquals(insertedRemote1.data, remote.data); Assertions.assertEquals(insertedRemote1.data, remote.data);
remote = new TypeManyToOneUUIDRemote(); remote = new TypeManyToOneUUIDRemote();
remote.data = "remote2"; remote.data = "remote2";
final TypeManyToOneUUIDRemote insertedRemote2 = DataAccess.insert(remote); final TypeManyToOneUUIDRemote insertedRemote2 = ConfigureDb.da.insert(remote);
Assertions.assertEquals(insertedRemote2.data, remote.data); Assertions.assertEquals(insertedRemote2.data, remote.data);
final TypeManyToOneUUIDRoot test = new TypeManyToOneUUIDRoot(); final TypeManyToOneUUIDRoot test = new TypeManyToOneUUIDRoot();
test.otherData = "kjhlkjlkj"; test.otherData = "kjhlkjlkj";
test.remoteUuid = insertedRemote2.uuid; test.remoteUuid = insertedRemote2.uuid;
final TypeManyToOneUUIDRoot insertedData = DataAccess.insert(test); final TypeManyToOneUUIDRoot insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData); Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.uuid); Assertions.assertNotNull(insertedData.uuid);
Assertions.assertEquals(test.otherData, insertedData.otherData); Assertions.assertEquals(test.otherData, insertedData.otherData);
Assertions.assertEquals(insertedRemote2.uuid, insertedData.remoteUuid); Assertions.assertEquals(insertedRemote2.uuid, insertedData.remoteUuid);
TypeManyToOneUUIDRoot retrieve = DataAccess.get(TypeManyToOneUUIDRoot.class, insertedData.uuid); TypeManyToOneUUIDRoot retrieve = ConfigureDb.da.get(TypeManyToOneUUIDRoot.class, insertedData.uuid);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.uuid); Assertions.assertNotNull(retrieve.uuid);
Assertions.assertEquals(insertedData.uuid, retrieve.uuid); Assertions.assertEquals(insertedData.uuid, retrieve.uuid);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertEquals(insertedRemote2.uuid, retrieve.remoteUuid); Assertions.assertEquals(insertedRemote2.uuid, retrieve.remoteUuid);
TypeManyToOneUUIDRootExpand retrieve2 = DataAccess.get(TypeManyToOneUUIDRootExpand.class, insertedData.uuid); TypeManyToOneUUIDRootExpand retrieve2 = ConfigureDb.da.get(TypeManyToOneUUIDRootExpand.class,
insertedData.uuid);
Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.uuid); Assertions.assertNotNull(retrieve2.uuid);
Assertions.assertEquals(insertedData.uuid, retrieve2.uuid); Assertions.assertEquals(insertedData.uuid, retrieve2.uuid);
@ -150,23 +158,23 @@ public class TestManyToOne {
Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data); Assertions.assertEquals(insertedRemote2.data, retrieve2.remote.data);
// remove values: // remove values:
final int count = DataAccess.delete(TypeManyToOneUUIDRemote.class, remote.uuid); final long count = ConfigureDb.da.delete(TypeManyToOneUUIDRemote.class, insertedRemote2.uuid);
Assertions.assertEquals(1, count); Assertions.assertEquals(1, count);
// check fail: // check fail:
retrieve = DataAccess.get(TypeManyToOneUUIDRoot.class, insertedData.uuid); retrieve = ConfigureDb.da.get(TypeManyToOneUUIDRoot.class, insertedData.uuid);
Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.uuid); Assertions.assertNotNull(retrieve.uuid);
Assertions.assertEquals(insertedData.uuid, retrieve.uuid); Assertions.assertEquals(insertedData.uuid, retrieve.uuid);
Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData);
Assertions.assertEquals(insertedRemote2.uuid, retrieve.remoteUuid); Assertions.assertEquals(insertedRemote2.uuid, retrieve.remoteUuid);
retrieve2 = DataAccess.get(TypeManyToOneUUIDRootExpand.class, insertedData.uuid); retrieve2 = ConfigureDb.da.get(TypeManyToOneUUIDRootExpand.class, insertedData.uuid);
Assertions.assertNotNull(retrieve2); Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.uuid); Assertions.assertNotNull(retrieve2.uuid);
Assertions.assertEquals(insertedData.uuid, retrieve2.uuid); Assertions.assertEquals(insertedData.uuid, retrieve2.uuid);
Assertions.assertEquals(insertedData.otherData, retrieve2.otherData); Assertions.assertEquals(insertedData.otherData, retrieve2.otherData);
Assertions.assertNull(retrieve2.remote); Assertions.assertNull(retrieve2.remote);
} }
} }

View File

@ -1,4 +1,4 @@
package test.kar.archidata; package test.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -11,17 +11,19 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.DataFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import test.kar.archidata.model.TypeOneToManyRemote; import test.kar.archidata.ConfigureDb;
import test.kar.archidata.model.TypeOneToManyRoot; import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.model.TypeOneToManyRootExpand; import test.kar.archidata.dataAccess.model.TypeOneToManyRemote;
import test.kar.archidata.model.TypeOneToManyUUIDRemote; import test.kar.archidata.dataAccess.model.TypeOneToManyRoot;
import test.kar.archidata.model.TypeOneToManyUUIDRoot; import test.kar.archidata.dataAccess.model.TypeOneToManyRootExpand;
import test.kar.archidata.model.TypeOneToManyUUIDRootExpand; import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRemote;
import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRoot;
import test.kar.archidata.dataAccess.model.TypeOneToManyUUIDRootExpand;
@ExtendWith(StepwiseExtension.class) @ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -45,9 +47,11 @@ public class TestOneToMany {
sqlCommand.addAll(DataFactory.createTable(TypeOneToManyRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeOneToManyRoot.class));
sqlCommand.addAll(DataFactory.createTable(TypeOneToManyUUIDRemote.class)); sqlCommand.addAll(DataFactory.createTable(TypeOneToManyUUIDRemote.class));
sqlCommand.addAll(DataFactory.createTable(TypeOneToManyUUIDRoot.class)); sqlCommand.addAll(DataFactory.createTable(TypeOneToManyUUIDRoot.class));
for (final String elem : sqlCommand) { if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
LOGGER.debug("request: '{}'", elem); for (final String elem : sqlCommand) {
DataAccess.executeSimpleQuery(elem); LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
} }
} }
@ -58,13 +62,13 @@ public class TestOneToMany {
final TypeOneToManyRoot root = new TypeOneToManyRoot(); final TypeOneToManyRoot root = new TypeOneToManyRoot();
root.otherData = "plouf"; root.otherData = "plouf";
final TypeOneToManyRoot insertedRoot = DataAccess.insert(root); final TypeOneToManyRoot insertedRoot = ConfigureDb.da.insert(root);
Assertions.assertEquals(insertedRoot.otherData, root.otherData); Assertions.assertEquals(insertedRoot.otherData, root.otherData);
Assertions.assertNull(insertedRoot.remoteIds); Assertions.assertNull(insertedRoot.remoteIds);
final TypeOneToManyRoot root2 = new TypeOneToManyRoot(); final TypeOneToManyRoot root2 = new TypeOneToManyRoot();
root2.otherData = "plouf 2"; root2.otherData = "plouf 2";
final TypeOneToManyRoot insertedRoot2 = DataAccess.insert(root2); final TypeOneToManyRoot insertedRoot2 = ConfigureDb.da.insert(root2);
Assertions.assertEquals(insertedRoot2.otherData, root2.otherData); Assertions.assertEquals(insertedRoot2.otherData, root2.otherData);
Assertions.assertNull(insertedRoot2.remoteIds); Assertions.assertNull(insertedRoot2.remoteIds);
@ -73,34 +77,34 @@ public class TestOneToMany {
final TypeOneToManyRemote remote10 = new TypeOneToManyRemote(); final TypeOneToManyRemote remote10 = new TypeOneToManyRemote();
remote10.data = "remote10"; remote10.data = "remote10";
remote10.rootId = insertedRoot.id; remote10.rootId = insertedRoot.id;
final TypeOneToManyRemote insertedRemote10 = DataAccess.insert(remote10); final TypeOneToManyRemote insertedRemote10 = ConfigureDb.da.insert(remote10);
Assertions.assertEquals(insertedRemote10.data, remote10.data); Assertions.assertEquals(insertedRemote10.data, remote10.data);
Assertions.assertEquals(insertedRemote10.rootId, remote10.rootId); Assertions.assertEquals(insertedRemote10.rootId, remote10.rootId);
final TypeOneToManyRemote remote11 = new TypeOneToManyRemote(); final TypeOneToManyRemote remote11 = new TypeOneToManyRemote();
remote11.data = "remote11"; remote11.data = "remote11";
remote11.rootId = insertedRoot.id; remote11.rootId = insertedRoot.id;
final TypeOneToManyRemote insertedRemote11 = DataAccess.insert(remote11); final TypeOneToManyRemote insertedRemote11 = ConfigureDb.da.insert(remote11);
Assertions.assertEquals(insertedRemote11.data, remote11.data); Assertions.assertEquals(insertedRemote11.data, remote11.data);
Assertions.assertEquals(insertedRemote11.rootId, remote11.rootId); Assertions.assertEquals(insertedRemote11.rootId, remote11.rootId);
final TypeOneToManyRemote remote20 = new TypeOneToManyRemote(); final TypeOneToManyRemote remote20 = new TypeOneToManyRemote();
remote20.data = "remote20"; remote20.data = "remote20";
remote20.rootId = insertedRoot2.id; remote20.rootId = insertedRoot2.id;
final TypeOneToManyRemote insertedRemote20 = DataAccess.insert(remote20); final TypeOneToManyRemote insertedRemote20 = ConfigureDb.da.insert(remote20);
Assertions.assertEquals(insertedRemote20.data, remote20.data); Assertions.assertEquals(insertedRemote20.data, remote20.data);
Assertions.assertEquals(insertedRemote20.rootId, remote20.rootId); Assertions.assertEquals(insertedRemote20.rootId, remote20.rootId);
// Check remote are inserted // Check remote are inserted
final TypeOneToManyRoot retreiveRoot1 = DataAccess.get(TypeOneToManyRoot.class, insertedRoot.id); final TypeOneToManyRoot retreiveRoot1 = ConfigureDb.da.get(TypeOneToManyRoot.class, insertedRoot.id);
Assertions.assertEquals(retreiveRoot1.otherData, insertedRoot.otherData); Assertions.assertEquals(retreiveRoot1.otherData, insertedRoot.otherData);
Assertions.assertNotNull(retreiveRoot1.remoteIds); Assertions.assertNotNull(retreiveRoot1.remoteIds);
Assertions.assertEquals(2, retreiveRoot1.remoteIds.size()); Assertions.assertEquals(2, retreiveRoot1.remoteIds.size());
Assertions.assertEquals(insertedRemote10.id, retreiveRoot1.remoteIds.get(0)); Assertions.assertEquals(insertedRemote10.id, retreiveRoot1.remoteIds.get(0));
Assertions.assertEquals(insertedRemote11.id, retreiveRoot1.remoteIds.get(1)); Assertions.assertEquals(insertedRemote11.id, retreiveRoot1.remoteIds.get(1));
final TypeOneToManyRoot retreiveRoot2 = DataAccess.get(TypeOneToManyRoot.class, insertedRoot2.id); final TypeOneToManyRoot retreiveRoot2 = ConfigureDb.da.get(TypeOneToManyRoot.class, insertedRoot2.id);
Assertions.assertEquals(retreiveRoot2.otherData, insertedRoot2.otherData); Assertions.assertEquals(retreiveRoot2.otherData, insertedRoot2.otherData);
Assertions.assertNotNull(retreiveRoot2.remoteIds); Assertions.assertNotNull(retreiveRoot2.remoteIds);
Assertions.assertEquals(1, retreiveRoot2.remoteIds.size()); Assertions.assertEquals(1, retreiveRoot2.remoteIds.size());
@ -108,7 +112,7 @@ public class TestOneToMany {
// Check remote are inserted and expandable // Check remote are inserted and expandable
final TypeOneToManyRootExpand retreiveRootExpand1 = DataAccess.get(TypeOneToManyRootExpand.class, final TypeOneToManyRootExpand retreiveRootExpand1 = ConfigureDb.da.get(TypeOneToManyRootExpand.class,
insertedRoot.id); insertedRoot.id);
Assertions.assertEquals(retreiveRootExpand1.otherData, insertedRoot.otherData); Assertions.assertEquals(retreiveRootExpand1.otherData, insertedRoot.otherData);
Assertions.assertNotNull(retreiveRootExpand1.remotes); Assertions.assertNotNull(retreiveRootExpand1.remotes);
@ -120,7 +124,7 @@ public class TestOneToMany {
Assertions.assertEquals(insertedRemote11.rootId, retreiveRootExpand1.remotes.get(1).rootId); Assertions.assertEquals(insertedRemote11.rootId, retreiveRootExpand1.remotes.get(1).rootId);
Assertions.assertEquals(insertedRemote11.data, retreiveRootExpand1.remotes.get(1).data); Assertions.assertEquals(insertedRemote11.data, retreiveRootExpand1.remotes.get(1).data);
final TypeOneToManyRootExpand retreiveRootExpand2 = DataAccess.get(TypeOneToManyRootExpand.class, final TypeOneToManyRootExpand retreiveRootExpand2 = ConfigureDb.da.get(TypeOneToManyRootExpand.class,
insertedRoot2.id); insertedRoot2.id);
Assertions.assertEquals(retreiveRootExpand2.otherData, insertedRoot2.otherData); Assertions.assertEquals(retreiveRootExpand2.otherData, insertedRoot2.otherData);
Assertions.assertNotNull(retreiveRootExpand2.remotes); Assertions.assertNotNull(retreiveRootExpand2.remotes);
@ -138,13 +142,13 @@ public class TestOneToMany {
final TypeOneToManyUUIDRoot root = new TypeOneToManyUUIDRoot(); final TypeOneToManyUUIDRoot root = new TypeOneToManyUUIDRoot();
root.otherData = "plouf"; root.otherData = "plouf";
final TypeOneToManyUUIDRoot insertedRoot = DataAccess.insert(root); final TypeOneToManyUUIDRoot insertedRoot = ConfigureDb.da.insert(root);
Assertions.assertEquals(insertedRoot.otherData, root.otherData); Assertions.assertEquals(insertedRoot.otherData, root.otherData);
Assertions.assertNull(insertedRoot.remoteIds); Assertions.assertNull(insertedRoot.remoteIds);
final TypeOneToManyUUIDRoot root2 = new TypeOneToManyUUIDRoot(); final TypeOneToManyUUIDRoot root2 = new TypeOneToManyUUIDRoot();
root2.otherData = "plouf 2"; root2.otherData = "plouf 2";
final TypeOneToManyUUIDRoot insertedRoot2 = DataAccess.insert(root2); final TypeOneToManyUUIDRoot insertedRoot2 = ConfigureDb.da.insert(root2);
Assertions.assertEquals(insertedRoot2.otherData, root2.otherData); Assertions.assertEquals(insertedRoot2.otherData, root2.otherData);
Assertions.assertNull(insertedRoot2.remoteIds); Assertions.assertNull(insertedRoot2.remoteIds);
@ -153,34 +157,34 @@ public class TestOneToMany {
final TypeOneToManyUUIDRemote remote10 = new TypeOneToManyUUIDRemote(); final TypeOneToManyUUIDRemote remote10 = new TypeOneToManyUUIDRemote();
remote10.data = "remote10"; remote10.data = "remote10";
remote10.rootUuid = insertedRoot.uuid; remote10.rootUuid = insertedRoot.uuid;
final TypeOneToManyUUIDRemote insertedRemote10 = DataAccess.insert(remote10); final TypeOneToManyUUIDRemote insertedRemote10 = ConfigureDb.da.insert(remote10);
Assertions.assertEquals(insertedRemote10.data, remote10.data); Assertions.assertEquals(insertedRemote10.data, remote10.data);
Assertions.assertEquals(insertedRemote10.rootUuid, remote10.rootUuid); Assertions.assertEquals(insertedRemote10.rootUuid, remote10.rootUuid);
final TypeOneToManyUUIDRemote remote11 = new TypeOneToManyUUIDRemote(); final TypeOneToManyUUIDRemote remote11 = new TypeOneToManyUUIDRemote();
remote11.data = "remote11"; remote11.data = "remote11";
remote11.rootUuid = insertedRoot.uuid; remote11.rootUuid = insertedRoot.uuid;
final TypeOneToManyUUIDRemote insertedRemote11 = DataAccess.insert(remote11); final TypeOneToManyUUIDRemote insertedRemote11 = ConfigureDb.da.insert(remote11);
Assertions.assertEquals(insertedRemote11.data, remote11.data); Assertions.assertEquals(insertedRemote11.data, remote11.data);
Assertions.assertEquals(insertedRemote11.rootUuid, remote11.rootUuid); Assertions.assertEquals(insertedRemote11.rootUuid, remote11.rootUuid);
final TypeOneToManyUUIDRemote remote20 = new TypeOneToManyUUIDRemote(); final TypeOneToManyUUIDRemote remote20 = new TypeOneToManyUUIDRemote();
remote20.data = "remote20"; remote20.data = "remote20";
remote20.rootUuid = insertedRoot2.uuid; remote20.rootUuid = insertedRoot2.uuid;
final TypeOneToManyUUIDRemote insertedRemote20 = DataAccess.insert(remote20); final TypeOneToManyUUIDRemote insertedRemote20 = ConfigureDb.da.insert(remote20);
Assertions.assertEquals(insertedRemote20.data, remote20.data); Assertions.assertEquals(insertedRemote20.data, remote20.data);
Assertions.assertEquals(insertedRemote20.rootUuid, remote20.rootUuid); Assertions.assertEquals(insertedRemote20.rootUuid, remote20.rootUuid);
// Check remote are inserted // Check remote are inserted
final TypeOneToManyUUIDRoot retreiveRoot1 = DataAccess.get(TypeOneToManyUUIDRoot.class, insertedRoot.uuid); final TypeOneToManyUUIDRoot retreiveRoot1 = ConfigureDb.da.get(TypeOneToManyUUIDRoot.class, insertedRoot.uuid);
Assertions.assertEquals(retreiveRoot1.otherData, insertedRoot.otherData); Assertions.assertEquals(retreiveRoot1.otherData, insertedRoot.otherData);
Assertions.assertNotNull(retreiveRoot1.remoteIds); Assertions.assertNotNull(retreiveRoot1.remoteIds);
Assertions.assertEquals(2, retreiveRoot1.remoteIds.size()); Assertions.assertEquals(2, retreiveRoot1.remoteIds.size());
Assertions.assertEquals(insertedRemote10.uuid, retreiveRoot1.remoteIds.get(0)); Assertions.assertEquals(insertedRemote10.uuid, retreiveRoot1.remoteIds.get(0));
Assertions.assertEquals(insertedRemote11.uuid, retreiveRoot1.remoteIds.get(1)); Assertions.assertEquals(insertedRemote11.uuid, retreiveRoot1.remoteIds.get(1));
final TypeOneToManyUUIDRoot retreiveRoot2 = DataAccess.get(TypeOneToManyUUIDRoot.class, insertedRoot2.uuid); final TypeOneToManyUUIDRoot retreiveRoot2 = ConfigureDb.da.get(TypeOneToManyUUIDRoot.class, insertedRoot2.uuid);
Assertions.assertEquals(retreiveRoot2.otherData, insertedRoot2.otherData); Assertions.assertEquals(retreiveRoot2.otherData, insertedRoot2.otherData);
Assertions.assertNotNull(retreiveRoot2.remoteIds); Assertions.assertNotNull(retreiveRoot2.remoteIds);
Assertions.assertEquals(1, retreiveRoot2.remoteIds.size()); Assertions.assertEquals(1, retreiveRoot2.remoteIds.size());
@ -188,7 +192,7 @@ public class TestOneToMany {
// Check remote are inserted and expandable // Check remote are inserted and expandable
final TypeOneToManyUUIDRootExpand retreiveRootExpand1 = DataAccess.get(TypeOneToManyUUIDRootExpand.class, final TypeOneToManyUUIDRootExpand retreiveRootExpand1 = ConfigureDb.da.get(TypeOneToManyUUIDRootExpand.class,
insertedRoot.uuid); insertedRoot.uuid);
Assertions.assertEquals(retreiveRootExpand1.otherData, insertedRoot.otherData); Assertions.assertEquals(retreiveRootExpand1.otherData, insertedRoot.otherData);
Assertions.assertNotNull(retreiveRootExpand1.remotes); Assertions.assertNotNull(retreiveRootExpand1.remotes);
@ -200,7 +204,7 @@ public class TestOneToMany {
Assertions.assertEquals(insertedRemote11.rootUuid, retreiveRootExpand1.remotes.get(1).rootUuid); Assertions.assertEquals(insertedRemote11.rootUuid, retreiveRootExpand1.remotes.get(1).rootUuid);
Assertions.assertEquals(insertedRemote11.data, retreiveRootExpand1.remotes.get(1).data); Assertions.assertEquals(insertedRemote11.data, retreiveRootExpand1.remotes.get(1).data);
final TypeOneToManyUUIDRootExpand retreiveRootExpand2 = DataAccess.get(TypeOneToManyUUIDRootExpand.class, final TypeOneToManyUUIDRootExpand retreiveRootExpand2 = ConfigureDb.da.get(TypeOneToManyUUIDRootExpand.class,
insertedRoot2.uuid); insertedRoot2.uuid);
Assertions.assertEquals(retreiveRootExpand2.otherData, insertedRoot2.otherData); Assertions.assertEquals(retreiveRootExpand2.otherData, insertedRoot2.otherData);
Assertions.assertNotNull(retreiveRootExpand2.remotes); Assertions.assertNotNull(retreiveRootExpand2.remotes);
@ -210,4 +214,4 @@ public class TestOneToMany {
Assertions.assertEquals(insertedRemote20.data, retreiveRootExpand2.remotes.get(0).data); Assertions.assertEquals(insertedRemote20.data, retreiveRootExpand2.remotes.get(0).data);
} }
} }

Some files were not shown because too many files have changed in this diff Show More