Compare commits

..

1 Commits
main ... plop

Author SHA1 Message Date
6ccce206b9 [FEAT] deploy on github
[DEV] deploy on gitea neofarm
2024-06-02 21:35:01 +02:00
180 changed files with 4765 additions and 11202 deletions

View File

@ -30,19 +30,16 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,16 +0,0 @@
---
name: "Assign PR Author as Assignee"
on:
pull_request:
types:
- opened
jobs:
assign-pr-author-as-assignee:
runs-on: ubuntu-latest
steps:
- name: "Assign Author as Assignee"
uses: itsOliverBott/assign-pr-author-as-assignee@latest
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,33 +0,0 @@
---
name: "Check PR title"
on:
pull_request:
types:
- opened
- edited
- synchronize
- ready_for_review
- reopened
jobs:
check-title:
runs-on: ubuntu-latest
steps:
- name: "Check title"
uses: Slashgear/action-check-pr-title@v4.3.0
with:
regexp: "\\[(API,)?(API|DEV-OPS|DOC|FEAT|FIX|FIX\\-CI|STYLE)\\]( \\([A-Za-z0-9.\\-]+\\))? [A-Za-z0-9 ,.'\\-!]+$"
helpMessage: |
Title of the PR MUST respect format: "[{TYPE}] clear description without typos in english" with {TYPE}:
* [API] Change API that permit to access on the application (un-compatibility only). This one can specifically added with [API,{TYPE}]
* [DEV-OPS] Update automatic build system, method to deliver application/packages, ...
* [DOC] Update or add some documentation.
* [FEAT] Develop a new feature
* [FIX] When fixing issue
* [FIX-CI] When the CI fail to build and we apply a correction to set it work again.
* [STYLE] Update of the style tools/checker, or add/remove rules.
Examples:
[FEAT] My beautiful feature
[API,FIX] Change API to fix typo
[FIX] (module) Correct part of ...

View File

@ -10,17 +10,19 @@ name: Java CI with Maven
on:
push:
branches:
- develop
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
@ -32,4 +34,4 @@ jobs:
# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
- name: Update dependency graph
uses: advanced-security/maven-dependency-submission-action@4f64ddab9d742a4806eeb588d238e4c311a8397d
uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6

View File

@ -11,12 +11,12 @@
</arguments>
</buildCommand>
<buildCommand>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<arguments>
</arguments>
</buildCommand>

110
pom.xml
View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.21.0</version>
<version>0.11.0</version>
<properties>
<java.version>21</java.version>
<maven.compiler.version>3.1</maven.compiler.version>
@ -14,13 +14,36 @@
<jaxb.version>2.3.1</jaxb.version>
<istack.version>4.1.1</istack.version>
</properties>
<!--
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
-->
<repositories>
<repository>
<id>gitea-neofarm</id>
<url>https://gitea.neo.farm/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>gitea-neofarm</id>
<url>https://gitea.neo.farm/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
<snapshotRepository>
<id>gitea-neofarm</id>
<url>https://gitea.neo.farm/api/packages/kangaroo-and-rabbit/maven</url>
</snapshotRepository>
<!--
<repository>
<id>gitea-neofarm</id>
<url>https://gitea.neo.farm/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
-->
<!--
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
@ -29,6 +52,15 @@
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</snapshotRepository>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/kangaroo-and-rabbit/archidata</url>
</repository>
<snapshotRepository>
<id>github</id>
<url>https://maven.pkg.github.com/kangaroo-and-rabbit/archidata</url>
</snapshotRepository>
-->
</distributionManagement>
<dependencyManagement>
<dependencies>
@ -54,30 +86,6 @@
<version>2.1.0-alpha1</version>
<scope>test</scope>
</dependency>
<!-- Decode webP images -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-webp</artifactId>
<version>3.11.0</version>
</dependency>
<!-- Decode JPEG image -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.11.0</version>
</dependency>
<!-- Encode file in webp -->
<dependency>
<groupId>com.github.gotson</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.2.2</version>
</dependency>
<!-- Detect type of a file with mime type -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>3.0.0-BETA2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
@ -120,13 +128,11 @@
<artifactId>istack-commons-runtime</artifactId>
<version>${istack.version}</version>
</dependency>
<!-- continu to be needed ??? -->
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<scope>test</scope>
</dependency>
<!-- Serialize and un-serialize request in JSON-->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
@ -134,41 +140,40 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.1</version>
<version>2.17.1</version>
</dependency>
<!-- encode output in CSV -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.18.1</version>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.1</version>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<version>6.1.0-M2</version>
<scope>provided</scope>
</dependency>
<!-- Interface for My-sql & sqlite DB -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.0.0</version>
<version>8.4.0</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.1.0</version>
<version>3.46.0.0</version>
</dependency>
<!-- Interface for JWT token -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.41.1</version>
<version>9.39.3</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
@ -179,38 +184,15 @@
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.2.23</version>
<version>2.2.22</version>
</dependency>
<!-- spotbug tooling -->
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>4.8.6</version>
<version>4.8.5</version>
<scope>compile</scope>
</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 **
@ -219,24 +201,24 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.24.1</version>
<version>2.24.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.5.0</version>
<version>3.3.1</version>
</dependency>
</dependencies>
<build>

View File

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

View File

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

View File

@ -0,0 +1,48 @@
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

@ -1,19 +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;
import jakarta.ws.rs.HttpMethod;
/**
* Indicates that the annotated method responds to HTTP ARCHIVE requests.
*
* @author Edouard DUPIN
* @see HttpMethod
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("ARCHIVE")
public @interface ARCHIVE {}

View File

@ -6,25 +6,19 @@ import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.morphia.annotations.Entity;
import dev.morphia.mapping.Mapper;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
@ -35,7 +29,6 @@ import jakarta.ws.rs.DefaultValue;
public class AnnotationTools {
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 {
if (options != null) {
final List<OverrideTableName> data = options.get(OverrideTableName.class);
@ -46,13 +39,16 @@ public class AnnotationTools {
return AnnotationTools.getTableName(clazz);
}
// For SQL declaration table Name
public static String getTableName(final Class<?> element) {
public static String getTableName(final Class<?> element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class);
if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name
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();
if (tmp == null) {
return element.getSimpleName();
@ -60,158 +56,161 @@ public class AnnotationTools {
return tmp;
}
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) {
public static boolean getSchemaReadOnly(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
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();
}
public static String getSchemaExample(final Class<?> element) {
public static String getSchemaExample(final Class<?> element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
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();
}
public static boolean getNoWriteSpecificMode(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NoWriteSpecificMode.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static String getSchemaDescription(final Class<?> element) {
public static String getSchemaDescription(final Class<?> element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).description();
}
public static String getSchemaDescription(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
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();
}
public static String getDefault(final Field element) {
public static String getSchemaDescription(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
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();
}
public static String getComment(final Field element) throws DataAccessException {
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);
if (annotation.length == 0) {
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();
}
public static ManyToOne getManyToOne(final Field element) {
public static ManyToOne getManyToOne(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToOne.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @ManyToOne on " + element.getClass().getCanonicalName());
}
return (ManyToOne) annotation[0];
}
public static ManyToMany getManyToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToMany.class);
if (annotation.length == 0) {
return null;
}
return (ManyToMany) annotation[0];
}
public static OneToMany getOneToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(OneToMany.class);
if (annotation.length == 0) {
return null;
}
return (OneToMany) annotation[0];
}
public static DataJson getDataJson(final Field element) {
public static DataJson getDataJson(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataJson.class);
if (annotation.length == 0) {
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];
}
public static Long getConstraintsMax(final Field element) {
public static Long getConstraintsMax(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Max.class);
if (annotation.length == 0) {
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();
}
public static Long getConstraintsMin(final Field element) {
public static Long getConstraintsMin(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Min.class);
if (annotation.length == 0) {
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();
}
public static int getLimitSize(final Field element) {
public static int getLimitSize(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
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();
return length <= 0 ? 0 : length;
}
public static Size getConstraintsSize(final Field element) {
public static Size getConstraintsSize(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Size.class);
if (annotation.length == 0) {
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];
}
public static String getConstraintsPattern(final Field element) {
public static String getConstraintsPattern(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Pattern.class);
if (annotation.length == 0) {
return null;
}
return ((Pattern) annotation[0]).regexp();
}
public static boolean getConstraintsEmail(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Email.class);
if (annotation.length == 0) {
return false;
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Pattern on " + element.getClass().getCanonicalName());
}
return true;
return ((Pattern) annotation[0]).regexp();
}
public static boolean isAnnotationGroup(final Field field, final Class<?> annotationType) {
@ -237,11 +236,15 @@ public class AnnotationTools {
return false;
}
public static String getFieldNameRaw(final Field element) {
public static String getFieldName(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return element.getName();
}
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
final String name = ((Column) annotation[0]).name();
if (name.isBlank()) {
return element.getName();
@ -249,35 +252,19 @@ public class AnnotationTools {
return name;
}
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) {
public static boolean getColumnNotNull(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
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();
}
public static boolean getNullable(final Field element) {
public static boolean getNullable(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Nullable.class);
if (annotation.length == 0) {
return false;
@ -285,15 +272,19 @@ public class AnnotationTools {
return true;
}
public static boolean getConstraintsNotNull(final Field element) {
public static boolean getConstraintsNotNull(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NotNull.class);
if (annotation.length == 0) {
return false;
}
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @NotNull on " + element.getClass().getCanonicalName());
}
return true;
}
public static Field getPrimaryKeyField(final Class<?> clazz) {
public static Field getPrimaryKeyField(final Class<?> clazz) throws DataAccessException {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@ -306,59 +297,59 @@ public class AnnotationTools {
return null;
}
public static boolean isPrimaryKey(final Field element) {
final Annotation[] annotationSQL = element.getDeclaredAnnotationsByType(Id.class);
if (annotationSQL.length > 0) {
return true;
public static boolean isPrimaryKey(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Id.class);
if (annotation.length == 0) {
return false;
}
final Annotation[] annotationMongo = element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class);
if (annotationMongo.length > 0) {
return true;
}
return false;
return true;
}
public static boolean isUnique(final Field element) {
public static boolean isUnique(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
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();
}
public static GenerationType getStrategy(final Field element) {
public static GenerationType getStrategy(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class);
if (annotation.length == 0) {
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();
}
public static boolean isDeletedField(final Field element) {
public static boolean isDeletedField(final Field element) throws DataAccessException {
return element.getDeclaredAnnotationsByType(DataDeleted.class).length != 0;
}
public static boolean isCreatedAtField(final Field element) {
public static boolean isCreatedAtField(final Field element) throws DataAccessException {
return element.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
}
public static boolean isUpdateAtField(final Field element) {
public static boolean isUpdateAtField(final Field element) throws DataAccessException {
return element.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
}
public static boolean isDefaultNotRead(final Field element) {
public static boolean isdefaultNotRead(final Field element) throws DataAccessException {
return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0;
}
public static boolean isIdField(final Field element) {
if (element.getDeclaredAnnotationsByType(Id.class).length != 0) {
return true;
}
return element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class).length != 0;
public static boolean isIdField(final Field element) throws DataAccessException {
return element.getDeclaredAnnotationsByType(Id.class).length != 0;
}
// Note: delete field can not be renamed with OptionRenameColumn
public static String getDeletedFieldName(final Class<?> clazz) {
public static String getDeletedFieldName(final Class<?> clazz) throws DataAccessException {
try {
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
@ -366,7 +357,7 @@ public class AnnotationTools {
continue;
}
if (AnnotationTools.isDeletedField(elem)) {
return AnnotationTools.getFieldNameRaw(elem);
return AnnotationTools.getFieldName(elem);
}
}
} catch (final Exception ex) {
@ -375,8 +366,7 @@ public class AnnotationTools {
return null;
}
// Note: update field can not be renamed with OptionRenameColumn
public static String getUpdatedFieldName(final Class<?> clazz) {
public static String getUpdatedFieldName(final Class<?> clazz) throws DataAccessException {
try {
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
@ -384,7 +374,7 @@ public class AnnotationTools {
continue;
}
if (AnnotationTools.isUpdateAtField(elem)) {
return AnnotationTools.getFieldNameRaw(elem);
return AnnotationTools.getFieldName(elem);
}
}
} catch (final Exception ex) {
@ -410,28 +400,16 @@ public class AnnotationTools {
return null;
}
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) {
public static List<String> getFieldsNames(final Class<?> clazz) throws DataAccessException {
return getFieldsNamesFilter(clazz, false);
}
public static List<String> getAllFieldsNames(final Class<?> clazz) {
public static List<String> getAllFieldsNames(final Class<?> clazz) throws DataAccessException {
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<>();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
@ -441,17 +419,17 @@ public class AnnotationTools {
if (!full && AnnotationTools.isGenericField(field)) {
continue;
}
out.add(AnnotationTools.getFieldNameRaw(field));
out.add(AnnotationTools.getFieldName(field));
}
return out;
}
public static boolean isGenericField(final Field elem) {
public static boolean isGenericField(final Field elem) throws DataAccessException {
return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem)
|| AnnotationTools.isUpdateAtField(elem) || AnnotationTools.isDeletedField(elem);
}
public static Field getFieldOfId(final Class<?> clazz) {
public static Field getFieldOfId(final Class<?> clazz) throws DataAccessException {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@ -464,13 +442,13 @@ public class AnnotationTools {
return null;
}
public static Field getFieldNamed(final Class<?> clazz, final String name) {
public static Field getFieldNamed(final Class<?> clazz, final String name) throws DataAccessException {
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)) {
if (AnnotationTools.getFieldName(field).equals(name)) {
return field;
}
}

View File

@ -5,9 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** When we wend to have only One type for read and write mode (Wrapping API). */
@Target({ ElementType.TYPE })
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoWriteSpecificMode {
@Deprecated(since = "0.5.2")
public @interface DataComment {
String value();
}

View File

@ -1,19 +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;
import jakarta.ws.rs.HttpMethod;
/**
* Indicates that the annotated method responds to HTTP RESTORE requests.
*
* @author Edouard DUPIN
* @see HttpMethod
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("RESTORE")
public @interface RESTORE {}

View File

@ -5,8 +5,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.PARAMETER })
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface FormDataOptional {
public @interface SQLWhere {
String clause();
}

View File

@ -21,7 +21,6 @@ import java.util.UUID;
import javax.imageio.ImageIO;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.security.PermitTokenInURI;
@ -87,7 +86,18 @@ public class DataResource {
return filePath;
}
public static String getFileDataOld(final UUID uuid) {
public static String getFileDataOld(final long tmpFolderId) {
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator
+ "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (final IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(final UUID uuid) {
final String stringUUID = uuid.toString();
final String part1 = stringUUID.substring(0, 2);
final String part2 = stringUUID.substring(2, 4);
@ -104,37 +114,11 @@ public class DataResource {
return filePath;
}
public static String getFileData(final ObjectId oid) {
final String stringOid = oid.toHexString();
String dir1 = stringOid.substring(0, 2);
String dir2 = stringOid.substring(2, 4);
String dir3 = stringOid.substring(4, 6);
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
final byte[] hashBytes = digest.digest(oid.toByteArray());
dir1 = String.format("%02x", hashBytes[0]);
dir2 = String.format("%02x", hashBytes[1]);
dir3 = String.format("%02x", hashBytes[2]);
} catch (final NoSuchAlgorithmException ex) {
LOGGER.error("Fail to generate the hash of the objectId ==> ise direct value ... {}", ex.getMessage());
}
final String finalPath = dir1 + File.separator + dir2 + File.separator + dir3;
String filePath = ConfigBaseVariable.getMediaDataFolder() + "_oid" + File.separator + finalPath
+ File.separator;
try {
createFolder(filePath);
} catch (final IOException e) {
e.printStackTrace();
}
filePath += stringOid;
return filePath;
public static String getFileMetaData(final UUID uuid) {
return getFileData(uuid) + ".json";
}
public static String getFileMetaData(final ObjectId oid) {
return getFileData(oid) + ".json";
}
public Data getWithSha512(final String sha512) {
public static Data getWithSha512(final String sha512) {
LOGGER.info("find sha512 = {}", sha512);
try {
return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)));
@ -145,7 +129,7 @@ public class DataResource {
return null;
}
public Data getWithId(final long id) {
public static Data getWithId(final long id) {
LOGGER.info("find id = {}", id);
try {
return DataAccess.get(Data.class, id);
@ -156,7 +140,7 @@ public class DataResource {
return null;
}
public Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
throws IOException {
// determine mime type:
Data injectedData = new Data();
@ -182,7 +166,7 @@ public class DataResource {
e.printStackTrace();
return null;
}
final String mediaPath = getFileData(injectedData.oid);
final String mediaPath = getFileData(injectedData.uuid);
LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
@ -190,9 +174,9 @@ public class DataResource {
return injectedData;
}
public static void modeFileOldModelToNewModel(final UUID uuid, final ObjectId oid) throws IOException {
String mediaCurentPath = getFileDataOld(uuid);
String mediaDestPath = getFileData(oid);
public static void modeFileOldModelToNewModel(final long id, final UUID uuid) throws IOException {
String mediaCurentPath = getFileDataOld(id);
String mediaDestPath = getFileData(uuid);
LOGGER.info("src = {}", mediaCurentPath);
LOGGER.info("dst = {}", mediaDestPath);
if (Files.exists(Paths.get(mediaCurentPath))) {
@ -268,9 +252,9 @@ public class DataResource {
return sb.toString();
}
public Data getSmall(final ObjectId oid) {
public Data getSmall(final UUID id) {
try {
return DataAccess.get(Data.class, oid);
return DataAccess.get(Data.class, id);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
@ -304,7 +288,7 @@ public class DataResource {
}
@GET
@Path("{oid}")
@Path("{uuid}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@ -313,17 +297,17 @@ public class DataResource {
@Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range,
@PathParam("oid") final ObjectId oid) throws FailException {
@PathParam("uuid") final UUID uuid) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
LOGGER.info("== DATA retrieveDataId ? oid={} user={}", oid, (gc == null ? "null" : gc.userByToken));
LOGGER.info("== DATA retrieveDataId ? id={} user={}", uuid, (gc == null ? "null" : gc.userByToken));
// logger.info("===================================================");
final Data value = getSmall(oid);
final Data value = getSmall(uuid);
if (value == null) {
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 {
return buildStream(getFileData(oid), range,
return buildStream(getFileData(uuid), range,
value.mimeType == null ? "application/octet-stream" : value.mimeType);
} catch (final Exception ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to build output stream", ex);
@ -331,7 +315,7 @@ public class DataResource {
}
@GET
@Path("thumbnail/{oid}")
@Path("thumbnail/{uuid}")
@RolesAllowed("USER")
@PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@ -341,19 +325,19 @@ public class DataResource {
@Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range,
@PathParam("oid") final ObjectId oid) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
LOGGER.info("== DATA retrieveDataThumbnailId ? {}", (gc == null ? "null" : gc.userByToken));
LOGGER.info("===================================================");
final Data value = getSmall(oid);
@PathParam("uuid") final UUID uuid) throws FailException {
// GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
// logger.info("== DATA retrieveDataThumbnailId ? {}", (gc==null?"null":gc.user));
// logger.info("===================================================");
final Data value = getSmall(uuid);
if (value == null) {
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();
}
final String filePathName = getFileData(oid);
final String filePathName = getFileData(uuid);
final File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).entity("{\"error\":\"media Does not exist: " + oid + "\"}")
return Response.status(404).entity("{\"error\":\"media Does not exist: " + uuid + "\"}")
.type("application/json").build();
}
if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png")
@ -366,43 +350,31 @@ public class DataResource {
} catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to READ the image", ex);
}
LOGGER.info("input size image: {}x{} type={}", inputImage.getWidth(), inputImage.getHeight(),
inputImage.getType());
final int scaledWidth = 250;
final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth()
* scaledWidth);
// creates output image
final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
// scales the input image to the output image
final Graphics2D g2d = outputImage.createGraphics();
LOGGER.info("output size image: {}x{}", scaledWidth, scaledHeight);
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
for (final String data : ImageIO.getWriterFormatNames()) {
LOGGER.info("availlable format: {}", data);
}
// create the output stream:
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// TODO: check how to remove buffer file !!! here, it is not needed at all...
//ImageIO.write(outputImage, "JPEG", baos);
//ImageIO.write(outputImage, "png", baos);
ImageIO.write(outputImage, "WebP", baos);
ImageIO.write(outputImage, "JPG", baos);
} catch (final IOException e) {
e.printStackTrace();
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain")
.build();
}
final byte[] imageData = baos.toByteArray();
LOGGER.info("output length {}", imageData.length);
// Response.ok(new ByteArrayInputStream(imageData)).build();
final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH,
imageData.length);
//out.type("image/jpeg");
out.type("image/webp");
//out.type("image/png");
out.type("image/jpeg");
// TODO: move this in a decorator !!!
final CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
@ -418,7 +390,7 @@ public class DataResource {
}
@GET
@Path("{oid}/{name}")
@Path("{uuid}/{name}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@ -427,17 +399,17 @@ public class DataResource {
@Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range,
@PathParam("oid") final ObjectId oid,
@PathParam("uuid") final UUID uuid,
@PathParam("name") final String name) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
LOGGER.info("== DATA retrieveDataFull ? id={} user={}", oid, (gc == null ? "null" : gc.userByToken));
LOGGER.info("== DATA retrieveDataFull ? id={} user={}", uuid, (gc == null ? "null" : gc.userByToken));
// logger.info("===================================================");
final Data value = getSmall(oid);
final Data value = getSmall(uuid);
if (value == null) {
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();
}
return buildStream(getFileData(oid), range,
return buildStream(getFileData(uuid), range,
value.mimeType == null ? "application/octet-stream" : value.mimeType);
}
@ -494,9 +466,8 @@ public class DataResource {
to = file.length() - 1;
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
// LOGGER.info("responseRange: {}", responseRange);
try {
final RandomAccessFile raf = new RandomAccessFile(file, "r");
// logger.info("responseRange: {}", responseRange);
try (final RandomAccessFile raf = new RandomAccessFile(file, "r")) {
raf.seek(from);
final long len = to - from + 1;
@ -516,7 +487,7 @@ public class DataResource {
}
}
public void undelete(final Long id) throws Exception {
public static void undelete(final Long id) throws Exception {
DataAccess.unsetDelete(Data.class, id);
}

View File

@ -58,4 +58,5 @@ public class MediaStreamer implements StreamingOutput {
public long getLenth() {
return this.length;
}
}

View File

@ -1,43 +0,0 @@
package org.kar.archidata.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Path("/proxy")
//@Produces(MediaType.APPLICATION_JSON)
public class ProxyResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ProxyResource.class);
@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getImageFromUrl(@QueryParam("url") final String url) {
if (url == null || url.isEmpty()) {
return Response.status(Status.BAD_REQUEST).entity("URL manquante").build();
}
final Client client = ClientBuilder.newClient();
try {
final WebTarget target = client.target(url);
final Response response = target.request().get();
if (response.getStatus() != 200) {
return Response.status(Status.BAD_GATEWAY).entity("Can not get the image : " + response.getStatus())
.build();
}
return Response.ok(response.readEntity(byte[].class)).header("Access-Control-Allow-Origin", "*")
.header("Content-Type", response.getHeaderString("Content-Type")).build();
} catch (final Exception e) {
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("SERVER internal error : " + e.getMessage())
.build();
}
}
}

View File

@ -14,7 +14,7 @@ public class ExceptionCatcher implements ExceptionMapper<Exception> {
public Response toResponse(final Exception exception) {
LOGGER.warn("Catch exception (not managed...):");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ret).type(MediaType.APPLICATION_JSON)
.build();

View File

@ -15,7 +15,7 @@ public class FailExceptionCatcher implements ExceptionMapper<FailException> {
public Response toResponse(final FailException exception) {
LOGGER.warn("Catch FailException: {}", exception.getLocalizedMessage());
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
if (exception.exception != null) {
exception.exception.printStackTrace();
}

View File

@ -8,35 +8,19 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
/**
* This class catches InputException and maps it to a HTTP response.
*/
public class InputExceptionCatcher implements ExceptionMapper<InputException> {
private static final Logger LOGGER = LoggerFactory.getLogger(InputExceptionCatcher.class);
/**
* This method is called when an InputException is thrown.
* It logs the exception and builds a response with the error details.
*
* @param exception the InputException that was thrown
* @return a Response object containing the error details
*/
@Override
public Response toResponse(final InputException exception) {
LOGGER.warn("Catch InputException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={} ==> '{}'=>'{}'", ret.oid, exception.missingVariable,
LOGGER.error("Error UUID={} ==> '{}'=>'{}'", ret.uuid, exception.missingVariable,
exception.getLocalizedMessage());
// exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
/**
* This method builds a RestErrorResponse object from the InputException.
*
* @param exception the InputException that was thrown
* @return a RestErrorResponse object containing the error details
*/
private RestErrorResponse build(final InputException exception) {
return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'",
exception.getMessage());

View File

@ -12,29 +12,16 @@ import jakarta.ws.rs.ext.ExceptionMapper;
public class JacksonExceptionCatcher implements ExceptionMapper<JacksonException> {
private static final Logger LOGGER = LoggerFactory.getLogger(JacksonExceptionCatcher.class);
/**
* This method is called when a JacksonException is thrown.
* It logs the exception, builds a response with the error details, and returns it.
*
* @param exception the JacksonException that was thrown
* @return a Response object containing the error details
*/
@Override
public Response toResponse(final JacksonException exception) {
LOGGER.warn("Catch exception Input data parsing:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ret).type(MediaType.APPLICATION_JSON)
.build();
}
/**
* Builds a RestErrorResponse object from the given exception.
*
* @param exception the Exception that was thrown
* @return a RestErrorResponse object containing the error details
*/
private RestErrorResponse build(final Exception exception) {
return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch JSON Exception",
exception.getMessage());

View File

@ -1,17 +1,16 @@
package org.kar.archidata.catcher;
import java.time.Instant;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.NoWriteSpecificMode;
import org.kar.archidata.tools.UuidUtils;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.core.Response;
@NoWriteSpecificMode
public class RestErrorResponse {
public ObjectId oid = new ObjectId();
public UUID uuid = UuidUtils.nextUUID();
@NotNull
@Column(length = 0)
public String name; // Mandatory for TS generic error

View File

@ -15,7 +15,7 @@ public class SystemExceptionCatcher implements ExceptionMapper<SystemException>
public Response toResponse(final SystemException exception) {
LOGGER.warn("Catch SystemException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}

View File

@ -14,13 +14,12 @@ public class WebApplicationExceptionCatcher implements ExceptionMapper<WebApplic
@Override
public Response toResponse(final WebApplicationException exception) {
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
return Response.status(exception.getResponse().getStatusInfo().toEnum()).entity(ret)
.type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(final WebApplicationException exception) {
exception.printStackTrace();
return new RestErrorResponse(exception.getResponse().getStatusInfo().toEnum(), "Catch system exception",
exception.getMessage());
}

View File

@ -1,14 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,34 +0,0 @@
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

@ -1,350 +0,0 @@
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

@ -1,947 +0,0 @@
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

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

View File

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

View File

@ -10,14 +10,11 @@ import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.DataIfNotExists;
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.OptionSpecifyType;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
@ -28,17 +25,13 @@ import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.GenerationType;
public class DataFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class);
static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class);
public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws DataAccessException {
final String typelocal = ConfigBaseVariable.getDBType();
if ("mysql".equals(typelocal)) {
public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws Exception {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
if (type == UUID.class) {
return "binary(16)";
}
if (type == ObjectId.class) {
return "binary(12)";
}
if (type == Long.class || type == long.class) {
return "bigint";
}
@ -89,13 +82,10 @@ public class DataFactory {
out.append(")");
return out.toString();
}
} else if ("sqlite".equals(typelocal)) {
} else {
if (type == UUID.class) {
return "BINARY(16)";
}
if (type == ObjectId.class) {
return "BINARY(12)";
}
if (type == Long.class || type == long.class) {
return "INTEGER";
}
@ -148,9 +138,6 @@ public class DataFactory {
out.append(" ) )");
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());
}
@ -165,9 +152,8 @@ public class DataFactory {
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final Class<?> classModel,
final QueryOptions options) throws Exception {
final String name = AnnotationTools.getFieldName(elem, options).inTable();
final Class<?> classModel) throws Exception {
final String name = AnnotationTools.getFieldName(elem);
final int limitSize = AnnotationTools.getLimitSize(elem);
final boolean notNull = AnnotationTools.getColumnNotNull(elem);
@ -176,10 +162,10 @@ public class DataFactory {
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
final String comment = AnnotationTools.getSchemaDescription(elem);
final String comment = AnnotationTools.getComment(elem);
final String defaultValue = AnnotationTools.getDefault(elem);
if (mainTableBuilder.toString().length() == 0) {
if (fieldId == 0) {
mainTableBuilder.append("\n\t\t`");
} else {
mainTableBuilder.append(",\n\t\t`");
@ -313,10 +299,7 @@ public class DataFactory {
}
}
private static boolean isFieldFromSuperClass(
final Class<?> model,
final String filedName,
final QueryOptions options) {
private static boolean isFieldFromSuperClass(final Class<?> model, final String filedName) {
final Class<?> superClass = model.getSuperclass();
if (superClass == null) {
return false;
@ -324,7 +307,7 @@ public class DataFactory {
for (final Field field : superClass.getFields()) {
String name;
try {
name = AnnotationTools.getFieldName(field, options).inTable();
name = AnnotationTools.getFieldName(field);
if (filedName.equals(name)) {
return true;
}
@ -372,7 +355,7 @@ public class DataFactory {
for (final Field elem : clazz.getFields()) {
// DEtect the primary key (support only one primary key right now...
if (AnnotationTools.isPrimaryKey(elem)) {
primaryKeys.add(AnnotationTools.getFieldName(elem, options).inTable());
primaryKeys.add(AnnotationTools.getFieldName(elem));
}
}
// 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).
@ -389,8 +372,8 @@ public class DataFactory {
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
final String dataName = AnnotationTools.getFieldName(elem, options).inTable();
if (isFieldFromSuperClass(currentClazz, dataName, options)) {
final String dataName = AnnotationTools.getFieldName(elem);
if (isFieldFromSuperClass(currentClazz, dataName)) {
LOGGER.trace(" SKIP: '{}'", elem.getName());
continue;
}
@ -399,46 +382,28 @@ public class DataFactory {
continue;
}
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());
if (DBAccessSQL.isAddOnField(elem)) {
final DataAccessAddOn addOn = DBAccessSQL.findAddOnforField(elem);
LOGGER.trace("Create type for: {} ==> {} (ADD-ON)",
AnnotationTools.getFieldName(elem, options).inTable(), basicType);
if (DataAccess.isAddOnField(elem)) {
final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem);
LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem),
elem.getType());
if (addOn != null) {
addOn.createTables(tableName, primaryField, elem, tmpOut, preActionList, postActionList,
createIfNotExist, createDrop, fieldId, options);
createIfNotExist, createDrop, fieldId);
} else {
throw new DataAccessException("Element matked as add-on but add-on does not loaded: table:"
+ tableName + " field name=" + AnnotationTools.getFieldName(elem, options).inTable()
+ " type=" + basicType);
+ tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type="
+ elem.getType());
}
} else {
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem, options).inTable(),
basicType);
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType());
DataFactory.createTablesSpecificType(tableName, tablePrimaryKeyField, elem, tmpOut, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, basicType, options);
postActionList, createIfNotExist, createDrop, fieldId, elem.getType());
}
fieldId++;
}
final boolean dataInThisObject = tmpOut.toString().length() > 0;
if (dataInThisObject) {
LOGGER.info("Previous Object : '{}'", reverseOut.toString());
final boolean dataInPreviousObject = reverseOut.toString().length() > 0;
if (dataInPreviousObject) {
tmpOut.append(", ");

View File

@ -5,10 +5,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryAnd implements QueryItem {
protected final List<QueryItem> childs;
@ -45,22 +41,14 @@ public class QueryAnd implements QueryItem {
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) {
elem.injectQuery(ioDb, ps, iii);
elem.injectQuery(ps, iii);
}
}
public int 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,16 +1,8 @@
package org.kar.archidata.dataAccess;
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 {
static final Logger LOGGER = LoggerFactory.getLogger(DBAccess.class);
private final String key;
private final String comparator;
private final Object value;
@ -40,28 +32,8 @@ public class QueryCondition implements QueryItem {
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
ioDb.addElement(ps, this.value, iii);
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
DataAccess.addElement(ps, this.value, iii);
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,10 +3,6 @@ package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryInList<T> implements QueryItem {
protected final String key;
protected final String comparator;
@ -48,15 +44,10 @@ public class QueryInList<T> implements QueryItem {
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final Object elem : this.value) {
ioDb.addElement(ps, elem, iii);
DataAccess.addElement(ps, elem, iii);
iii.inc();
}
}
@Override
public void generateFilter(final List<Bson> filters) {
filters.add(Filters.in(this.key, this.value));
}
}

View File

@ -1,17 +1,9 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
public interface QueryItem {
// For SQL mode query construction
void generateQuery(StringBuilder query, String tableName);
// 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);
void injectQuery(PreparedStatement ps, CountInOut iii) throws Exception;
}

View File

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

View File

@ -1,11 +1,6 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryNull implements QueryItem {
private final String key;
@ -25,12 +20,5 @@ public class QueryNull implements QueryItem {
}
@Override
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));
}
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {}
}

View File

@ -1,13 +1,8 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryOr implements QueryItem {
protected final List<QueryItem> childs;
@ -39,18 +34,9 @@ public class QueryOr implements QueryItem {
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) {
elem.injectQuery(ioDb, ps, iii);
elem.injectQuery(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

@ -0,0 +1,322 @@
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.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.ObjectMapper;
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 Exception {
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 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));
}
public static void addLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));// TODO: ,new OverrideFieldName("covers", column));
}
public static void addLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void addLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
}
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
return;
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<Long> newList = new ArrayList<>();
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<UUID> newList = new ArrayList<>();
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongLong data = DataAccess.get(TableCoversLongLong.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<Long> newList = new ArrayList<>();
for (final Long elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
}
final List<UUID> newList = new ArrayList<>();
for (final UUID elem : data.covers) {
if (elem.equals(remoteKey)) {
continue;
}
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
/* public static <TYPE> void addLink(final Class<TYPE> clazz, final Object localKey, final String column, final Object remoteKey) throws Exception { final String tableName =
* AnnotationTools.getTableName(clazz); final TYPE data = DataAccess.get(clazz, localKey); // TODO: add filter of the "column" // find the field column: // add the remoteKey in the list: // post
* new data in the DB final String linkTableName = generateLinkTableName(this.tableName, this.column); final LinkTable insertElement = new LinkTable(this.localKey, this.remoteKey);
* DataAccess.insert(insertElement, new OverrideTableName(linkTableName)); } */
}

View File

@ -0,0 +1,543 @@
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.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.AnnotationTools;
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.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryInList;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.addOn.model.LinkTableLongLong;
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.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 String getSQLFieldType(final Field elem) {
return null;
}
@Override
public boolean isCompatibleField(final Field elem) {
final ManyToMany decorators = elem.getDeclaredAnnotation(ManyToMany.class);
return decorators != null;
}
@Override
public void insertData(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) throws Exception {
final String name = AnnotationTools.getFieldName(field);
return generateLinkTableName(tableName, name);
}
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 String linkTableName = generateLinkTableName(tableName, name);
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);
querySelect.append(".object2Id ");
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(".");
querySelect.append("object1Id ");
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(" GROUP BY ");
querySelect.append(tmpVariable);
querySelect.append(".object1Id");
}
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 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 = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG);
field.set(data, idList);
count.inc();
return;
} else if (objectClass == UUID.class) {
final List<UUID> idList = DataAccess.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 = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG);
// field.set(data, idList);
count.inc();
if (idList != null && idList.size() > 0) {
final String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass));
// 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 = DataAccess.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField, childs)));
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
} else if (foreignKeyType == UUID.class) {
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value);
// field.set(data, idList);
count.inc();
if (idList != null && idList.size() > 0) {
final String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass));
// 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 = DataAccess.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField, 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 String tableName,
final Object localKey,
final Field field,
final Object data,
final List<LazyGetter> actions) 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 String columnName = AnnotationTools.getFieldName(field);
final String linkTableName = generateLinkTableName(tableName, columnName);
if (localKey instanceof final Long localKeyLong) {
if (objectClass == Long.class) {
actions.add(() -> {
DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName),
new Condition(new QueryCondition("object1Id", "=", localKeyLong)));
});
asyncInsert(tableName, localKey, field, data, actions);
} 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
public boolean isInsertAsync(final Field field) {
return true;
}
@Override
public void asyncInsert(
final String tableName,
final Object localKey,
final Field field,
final Object data,
final List<LazyGetter> actions) 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 String columnName = AnnotationTools.getFieldName(field);
final String linkTableName = generateLinkTableName(tableName, columnName);
if (localKey instanceof final Long localKeyLong) {
if (objectClass == Long.class) {
// ========================================================
// == Link a "Long" primary Key with List<Long>
// ========================================================
@SuppressWarnings("unchecked")
final List<Long> dataCasted = (List<Long>) data;
if (dataCasted.size() == 0) {
return;
}
final List<LinkTableLongLong> 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 LinkTableLongLong(localKeyLong, 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 "Long" primary Key with List<UUID>
// ========================================================
@SuppressWarnings("unchecked")
final List<UUID> dataCasted = (List<UUID>) data;
if (dataCasted.size() == 0) {
return;
}
final List<LinkTableLongUUID> 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 LinkTableLongUUID(localKeyLong, 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 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 {
throw new DataAccessException("Not manage access of remte key like ManyToMany other than Long or UUID: "
+ localKey.getClass().getCanonicalName());
}
}
@Override
public void drop(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.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
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 {
final String linkTableName = generateLinkTableNameField(tableName, field);
final QueryOptions options = new QueryOptions(new OverrideTableName(linkTableName));
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 Class<?> primaryType = primaryField.getType();
if (primaryType == Long.class) {
if (objectClass == Long.class) {
final List<String> sqlCommand = DataFactory.createTable(LinkTableLongLong.class, options);
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

@ -1,4 +1,4 @@
package org.kar.archidata.dataAccess.addOnSQL;
package org.kar.archidata.dataAccess.addOn;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
@ -8,9 +8,9 @@ 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.DBAccessSQL;
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;
@ -32,10 +32,10 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
@Override
public String getSQLFieldType(final Field field, final QueryOptions options) throws Exception {
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
public String getSQLFieldType(final Field field) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field);
try {
return DataFactory.convertTypeInSQL(field.getType(), fieldName.inTable());
return DataFactory.convertTypeInSQL(field.getType(), fieldName);
} catch (final Exception e) {
e.printStackTrace();
}
@ -48,12 +48,8 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
@Override
public void insertData(
final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii) throws Exception {
public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii)
throws Exception {
final Object data = field.get(rootObject);
if (data == null) {
if (field.getType() == Long.class) {
@ -153,7 +149,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
if (field.getType() == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
// TODO: rework this to have a lazy mode ...
DBAccessSQL.generateSelectField(querySelect, query, field.getType(), options, count);
DataAccess.generateSelectField(querySelect, query, field.getType(), options, count);
final Class<?> subType = field.getType();
final String subTableName = AnnotationTools.getTableName(subType);
final Field idField = AnnotationTools.getFieldOfId(subType);
@ -162,11 +158,11 @@ public class AddOnManyToOne implements DataAccessAddOn {
query.append("` ON ");
query.append(subTableName);
query.append(".");
query.append(AnnotationTools.getFieldName(idField, options).inTable());
query.append(AnnotationTools.getFieldName(idField));
query.append(" = ");
query.append(tableName);
query.append(".");
query.append(AnnotationTools.getFieldName(field, options).inTable());
query.append(AnnotationTools.getFieldName(field));
} else {
querySelect.append(" ");
querySelect.append(tableName);
@ -182,7 +178,6 @@ public class AddOnManyToOne implements DataAccessAddOn {
@Override
public void fillFromQuery(
final DBAccessSQL ioDb,
final ResultSet rs,
final Field field,
final Object data,
@ -238,8 +233,8 @@ public class AddOnManyToOne implements DataAccessAddOn {
if (objectClass == decorators.targetEntity()) {
if (decorators.fetch() == FetchType.EAGER) {
final CountInOut countNotNull = new CountInOut(0);
final Object dataNew = ioDb.createObjectFromSQLRequest(rs, objectClass, count, countNotNull, options,
lazyCall);
final Object dataNew = DataAccess.createObjectFromSQLRequest(rs, objectClass, count, countNotNull,
options, lazyCall);
if (dataNew != null && countNotNull.value != 0) {
field.set(data, dataNew);
}
@ -255,7 +250,7 @@ public class AddOnManyToOne implements DataAccessAddOn {
// 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);
final Object foreignData = DataAccess.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) {
return;
}
@ -265,13 +260,13 @@ public class AddOnManyToOne implements DataAccessAddOn {
}
} 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 = ioDb.getListOfRawUUID(rs, count.value);
final UUID foreignKey = DataAccess.getListOfRawUUID(rs, count.value);
count.inc();
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);
final Object foreignData = DataAccess.get(decorators.targetEntity(), foreignKey);
if (foreignData == null) {
return;
}
@ -294,17 +289,16 @@ public class AddOnManyToOne implements DataAccessAddOn {
final List<String> postActionList,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final QueryOptions options) throws Exception {
final int fieldId) 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);
postActionList, createIfNotExist, createDrop, fieldId, classType);
} 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);
postActionList, createIfNotExist, createDrop, fieldId, Long.class);
}
}
}

View File

@ -1,4 +1,4 @@
package org.kar.archidata.dataAccess.addOnSQL;
package org.kar.archidata.dataAccess.addOn;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
@ -11,9 +11,9 @@ import java.util.UUID;
import java.util.stream.Collectors;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessSQL;
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.QueryCondition;
@ -65,10 +65,10 @@ public class AddOnOneToMany implements DataAccessAddOn {
}
@Override
public String getSQLFieldType(final Field field, final QueryOptions options) throws Exception {
final FieldName fieldName = AnnotationTools.getFieldName(field, options);
public String getSQLFieldType(final Field field) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field);
try {
return DataFactory.convertTypeInSQL(Long.class, fieldName.inTable());
return DataFactory.convertTypeInSQL(Long.class, fieldName);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
@ -83,12 +83,8 @@ public class AddOnOneToMany implements DataAccessAddOn {
}
@Override
public void insertData(
final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii) throws SQLException, IllegalArgumentException, IllegalAccessException {
public void insertData(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");
}
@ -137,15 +133,15 @@ public class AddOnOneToMany implements DataAccessAddOn {
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 remoteTablePrimaryKeyName = AnnotationTools
.getFieldName(AnnotationTools.getPrimaryKeyField(targetEntity));
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(remoteTablePrimaryKeyName);
querySelect.append(" ");
if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(", ");
@ -223,7 +219,6 @@ public class AddOnOneToMany implements DataAccessAddOn {
@Override
public void fillFromQuery(
final DBAccessSQL ioDb,
final ResultSet rs,
final Field field,
final Object data,
@ -241,12 +236,12 @@ public class AddOnOneToMany implements DataAccessAddOn {
return;
}
if (objectClass == Long.class) {
final List<Long> idList = ioDb.getListOfIds(rs, count.value, SEPARATOR_LONG);
final List<Long> idList = DataAccess.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);
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value);
field.set(data, idList);
count.inc();
return;
@ -260,7 +255,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
parentIdTmp = Long.valueOf(modelData);
count.inc();
} catch (final NumberFormatException ex) {
final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
final List<UUID> idList = DataAccess.getListOfRawUUIDs(rs, count.value);
parendUuidTmp = idList.get(0);
count.inc();
}
@ -284,7 +279,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
// In the lazy mode, the request is done in asynchronous mode, they will be done after...
final LazyGetter lambda = () -> {
@SuppressWarnings("unchecked")
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(mappingKey, "=", parentId)));
if (foreignData == null) {
return;
@ -295,7 +290,7 @@ public class AddOnOneToMany implements DataAccessAddOn {
} else if (parendUuid != null) {
final LazyGetter lambda = () -> {
@SuppressWarnings("unchecked")
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(),
new Condition(new QueryCondition(mappingKey, "=", parendUuid)));
if (foreignData == null) {
return;
@ -308,4 +303,18 @@ 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,25 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,27 @@
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

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

View File

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

View File

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

View File

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

View File

@ -1,174 +0,0 @@
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,475 +0,0 @@
package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
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.DBAccess;
import org.kar.archidata.dataAccess.DBAccessMorphia;
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.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.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 DBAccessMorphia ioDb,
final Field field,
final Object rootObject,
final QueryOptions options,
final Document docSet,
final Document docUnSet) throws Exception {
}
@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];
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()) {
generateConcatQuery(tableName, primaryKey, field, querySelect, query, name, count, options);
}
}
@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 ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return;
}
final String fieldName = AnnotationTools.getFieldName(field);
if (!doc.containsKey(fieldName)) {
field.set(data, null);
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 (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 String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass));
// 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, 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 String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass));
// 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, 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 DBAccessMorphia 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 DBAccessMorphia 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<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 Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
ioDb.drop(LinkTableGeneric.class, new OverrideTableName(linkTableName),
new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
}
@Override
public void cleanAll(
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 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() + ">");
}
ioDb.cleanAll(LinkTableGeneric.class, new OverrideTableName(linkTableName),
new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
}
public static void addLink(
final DBAccess ioDb,
final Class<?> clazz,
final long localKey,
final String column,
final long remoteKey) throws Exception {
if (ioDb instanceof final DBAccessMorphia daSQL) {
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 LinkTableGeneric insertElement = new LinkTableGeneric(localKey, remoteKey);
daSQL.insert(insertElement, new OverrideTableName(linkTableName),
new OptionSpecifyType("object1Id", Long.class), new OptionSpecifyType("object2Id", Long.class));
} 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 long localKey,
final String column,
final long remoteKey) throws Exception {
if (ioDb instanceof final DBAccessMorphia 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", Long.class), new OptionSpecifyType("object2Id", Long.class));
} 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,233 +0,0 @@
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

@ -1,312 +0,0 @@
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,287 +0,0 @@
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

@ -1,465 +0,0 @@
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,158 +0,0 @@
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

@ -1,25 +0,0 @@
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

@ -1,25 +0,0 @@
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,7 +3,6 @@ package org.kar.archidata.dataAccess.options;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.QueryOptions;
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
@ -11,18 +10,13 @@ public interface CheckFunctionInterface {
/** This function implementation is design to check if the updated class is valid of not for insertion
* @param baseName NAme of the object to be precise with the use of what fail.
* @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 filterValue 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. */
void check(
final DBAccess ioDb,
final String baseName,
Object data,
List<String> modifiedValue,
final QueryOptions options) throws Exception;
void check(final String baseName, Object data, List<String> filterValue, final QueryOptions options)
throws Exception;
default void checkAll(final DBAccess ioDb, final String baseName, final Object data, final QueryOptions options)
throws Exception {
check(ioDb, baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options);
default void checkAll(final String baseName, final Object data, final QueryOptions options) throws Exception {
check(baseName, data, AnnotationTools.getAllFieldsNames(data.getClass()), options);
}
}

View File

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

View File

@ -14,7 +14,6 @@ import java.util.regex.Pattern;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryOptions;
@ -36,29 +35,15 @@ public class CheckJPA<T> implements CheckFunctionInterface {
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
public interface CheckInterface<K> {
/** 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 data The object that might be injected.
* @param modifiedValue List of fields that modification is requested.
* @param options Some query option that the checker can need to generate basic check.
* @param filterValue 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. */
void check(
final DBAccess ioDb,
final String baseName,
final K data,
List<String> modifiedValue,
final QueryOptions options) throws Exception;
void check(final String baseName, final K data, final QueryOptions options) throws Exception;
}
protected Map<String, List<CheckInterface<T>>> checking = null;
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));
}
protected void add(final String field, final CheckInterface<T> checkFunction) {
List<CheckInterface<T>> actions = this.checking.get(field);
if (actions == null) {
actions = new ArrayList<>();
@ -82,192 +67,128 @@ public class CheckJPA<T> implements CheckFunctionInterface {
for (final Field field : this.clazz.getFields()) {
final String fieldName = field.getName(); // AnnotationTools.getFieldName(field);
if (AnnotationTools.isPrimaryKey(field)) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
throw new InputException(baseName + fieldName,
"This is a '@Id' (primaryKey) ==> can not be change");
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
throw new InputException(baseName + fieldName,
"This is a '@Id' (primaryKey) ==> can not be change");
});
}
if (AnnotationTools.getConstraintsNotNull(field)) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
if (field.get(data) == null) {
throw new InputException(baseName + fieldName, "Can not be null");
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
if (field.get(data) == null) {
throw new InputException(baseName + fieldName, "Can not be null");
}
});
}
if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
throw new InputException(baseName + fieldName, "It is forbidden to change this field");
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
throw new InputException(baseName + fieldName, "It is forbidden to change this field");
});
}
final Class<?> type = field.getType();
if (type == Long.class || type == long.class) {
final Long maxValue = AnnotationTools.getConstraintsMax(field);
if (maxValue != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName,
"Value too height max: " + maxValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, "Value too height max: " + maxValue);
}
});
}
final Long minValue = AnnotationTools.getConstraintsMin(field);
if (minValue != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName,
"Value too Low min: " + minValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, "Value too Low min: " + minValue);
}
});
}
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
final Condition conditionCheck = condCheckers.isEmpty() ? null
: condCheckers.get(0).toCondition();
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem,
conditionCheck);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
final Condition conditionCheck = condCheckers.isEmpty() ? null
: condCheckers.get(0).toCondition();
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem,
conditionCheck);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
}
} else if (type == Integer.class || type == int.class) {
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
if (maxValueRoot != null) {
final int maxValue = maxValueRoot.intValue();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName,
"Value too height max: " + maxValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, "Value too height max: " + maxValue);
}
});
}
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
if (minValueRoot != null) {
final int minValue = minValueRoot.intValue();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName,
"Value too Low min: " + minValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, "Value too Low min: " + minValue);
}
});
}
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
}
} else if (type == UUID.class) {
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
}
} else if (type == Boolean.class || type == boolean.class) {
@ -275,87 +196,59 @@ public class CheckJPA<T> implements CheckFunctionInterface {
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
if (maxValueRoot != null) {
final float maxValue = maxValueRoot.floatValue();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName,
"Value too height max: " + maxValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, "Value too height max: " + maxValue);
}
});
}
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
if (minValueRoot != null) {
final float minValue = minValueRoot.floatValue();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName,
"Value too Low min: " + minValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, "Value too Low min: " + minValue);
}
});
}
} else if (type == Double.class || type == double.class) {
final Long maxValueRoot = AnnotationTools.getConstraintsMax(field);
if (maxValueRoot != null) {
final double maxValue = maxValueRoot.doubleValue();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName,
"Value too height max: " + maxValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, "Value too height max: " + maxValue);
}
});
}
final Long minValueRoot = AnnotationTools.getConstraintsMin(field);
if (minValueRoot != null) {
final double minValue = minValueRoot.doubleValue();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName,
"Value too Low min: " + minValue);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, "Value too Low min: " + minValue);
}
});
}
} else if (type == Date.class || type == Timestamp.class) {
@ -366,91 +259,51 @@ public class CheckJPA<T> implements CheckFunctionInterface {
} else if (type == String.class) {
final int maxSizeString = AnnotationTools.getLimitSize(field);
if (maxSizeString > 0) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (elemTyped.length() > maxSizeString) {
throw new InputException(baseName + fieldName,
"Too long size must be <= " + maxSizeString);
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (elemTyped.length() > maxSizeString) {
throw new InputException(baseName + fieldName,
"Too long size must be <= " + maxSizeString);
}
});
}
final Size limitSize = AnnotationTools.getConstraintsSize(field);
if (limitSize != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (elemTyped.length() > limitSize.max()) {
throw new InputException(baseName + fieldName,
"Too long size (constraints) must be <= " + limitSize.max());
}
if (elemTyped.length() < limitSize.min()) {
throw new InputException(baseName + fieldName,
"Too small size (constraints) must be >= " + limitSize.min());
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (elemTyped.length() > limitSize.max()) {
throw new InputException(baseName + fieldName,
"Too long size (constraints) must be <= " + limitSize.max());
}
if (elemTyped.length() < limitSize.min()) {
throw new InputException(baseName + fieldName,
"Too small size (constraints) must be >= " + limitSize.min());
}
});
}
final String patternString = AnnotationTools.getConstraintsPattern(field);
if (patternString != null) {
final Pattern pattern = Pattern.compile(patternString);
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (!pattern.matcher(elemTyped).find()) {
throw new InputException(baseName + fieldName,
"does not match the required pattern (constraints) must be '"
+ patternString + "'");
}
});
}
if (AnnotationTools.getConstraintsEmail(field)) {
final String emailPattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
final Pattern pattern = Pattern.compile(emailPattern);
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (!pattern.matcher(elemTyped).find()) {
throw new InputException(baseName + fieldName,
"does not match the required pattern[email] (constraints) must be '"
+ emailPattern + "'");
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (!pattern.matcher(elemTyped).find()) {
throw new InputException(baseName + fieldName,
"does not match the required pattern (constraints) must be '" + patternString
+ "'");
}
});
}
} else if (type == JsonValue.class) {
final DataJson jsonAnnotation = AnnotationTools.getDataJson(field);
@ -458,59 +311,31 @@ public class CheckJPA<T> implements CheckFunctionInterface {
// Here if we have an error it crash at start and no new instance after creation...
final CheckFunctionInterface instance = jsonAnnotation.checker().getDeclaredConstructor()
.newInstance();
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
instance.checkAll(ioDb, baseName + fieldName + ".", field.get(data), options);
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
instance.checkAll(baseName + fieldName + ".", field.get(data), options);
});
}
} else if (type.isEnum()) {
// 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...
if (AnnotationTools.isUnique(field)) {
// Create the request ...
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
Object other = null;
if (condCheckers.isEmpty()) {
other = DataAccess.getWhere(this.clazz,
new Condition(new QueryCondition(fieldName, "==", field.get(data))));
} else {
other = DataAccess.getWhere(this.clazz,
new Condition(new QueryCondition(fieldName, "==", field.get(data))),
condCheckers.get(0).toCondition());
}
if (other != null) {
throw new InputException(baseName + fieldName, "Name already exist in the DB");
}
});
add(fieldName, (final String baseName, final T data, final QueryOptions options) -> {
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
Object other = null;
if (condCheckers.isEmpty()) {
other = DataAccess.getWhere(this.clazz,
new Condition(new QueryCondition(fieldName, "==", field.get(data))));
} else {
other = DataAccess.getWhere(this.clazz,
new Condition(new QueryCondition(fieldName, "==", field.get(data))),
condCheckers.get(0).toCondition());
}
if (other != null) {
throw new InputException(baseName + fieldName, "Name already exist in the DB");
}
});
}
}
@ -520,56 +345,33 @@ 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
public void check(
final DBAccess ioDb,
final String baseName,
final Object data,
List<String> modifiedValue,
final List<String> filterValue,
final QueryOptions options) throws Exception {
if (this.checking == null) {
initialize();
}
if (modifiedValue == null) {
modifiedValue = AnnotationTools.getAllFieldsNames(this.clazz);
}
if (!(this.clazz.isAssignableFrom(data.getClass()))) {
throw new DataAccessException("Incompatatyble type of Object" + data.getClass().getCanonicalName());
}
@SuppressWarnings("unchecked")
final T dataCasted = (T) data;
for (final String filter : modifiedValue) {
for (final String filter : filterValue) {
final List<CheckInterface<T>> actions = this.checking.get(filter);
if (actions == null) {
continue;
}
for (final CheckInterface<T> action : actions) {
action.check(ioDb, baseName, dataCasted, modifiedValue, options);
action.check(baseName, dataCasted, options);
}
}
checkTyped(dataCasted, modifiedValue, options);
checkTyped(dataCasted, filterValue, options);
}
public void checkTyped(final T data, final List<String> modifiedValue, final QueryOptions options)
throws Exception {
public void checkTyped(final T data, final List<String> filterValue, final QueryOptions options) throws Exception {
// nothing to do ...
}
}

View File

@ -1,17 +1,11 @@
package org.kar.archidata.dataAccess.options;
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.DBAccessSQL;
import org.kar.archidata.dataAccess.QueryItem;
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. */
public class Condition extends QueryOption {
public final QueryItem condition;
@ -30,9 +24,9 @@ public class Condition extends QueryOption {
}
}
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
if (this.condition != null) {
this.condition.injectQuery(ioDb, ps, iii);
this.condition.injectQuery(ps, iii);
}
}
@ -68,26 +62,4 @@ public class Condition extends QueryOption {
}
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

@ -0,0 +1,51 @@
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 org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.DBAccessSQL;
import org.kar.archidata.dataAccess.DataAccess;
public class Limit extends QueryOption {
protected final long limit;
@ -16,12 +16,8 @@ public class Limit extends QueryOption {
query.append(" LIMIT ? \n");
}
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
ioDb.addElement(ps, this.limit, iii);
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
DataAccess.addElement(ps, this.limit, iii);
iii.inc();
}
public long getValue() {
return this.limit;
}
}

View File

@ -1,12 +0,0 @@
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

@ -1,20 +0,0 @@
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,9 +3,7 @@ package org.kar.archidata.dataAccess.options;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.Document;
import org.kar.archidata.dataAccess.CountInOut;
import org.kar.archidata.dataAccess.options.OrderItem.Order;
public class OrderBy extends QueryOption {
protected final List<OrderItem> childs;
@ -42,10 +40,4 @@ public class OrderBy extends QueryOption {
public void injectQuery(final PreparedStatement ps, final CountInOut iii) throws Exception {
// 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

@ -0,0 +1,92 @@
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

@ -0,0 +1,94 @@
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) {
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

@ -1,165 +0,0 @@
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

@ -1,82 +0,0 @@
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

@ -1,65 +0,0 @@
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

@ -1,83 +0,0 @@
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

@ -1,56 +0,0 @@
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

@ -1,18 +1,17 @@
package org.kar.archidata.exception;
import org.bson.types.ObjectId;
import java.util.UUID;
public class RESTErrorResponseException extends Exception {
private static final long serialVersionUID = 1L;
public ObjectId oid;
public class RESTErrorResponseExeption extends Exception {
public UUID uuid;
public String time;
public String name;
public String message;
public int status;
public String statusMessage;
public RESTErrorResponseException() {
this.oid = new ObjectId();
public RESTErrorResponseExeption() {
this.uuid = null;
this.time = null;
this.name = null;
this.message = null;
@ -20,9 +19,9 @@ public class RESTErrorResponseException extends Exception {
this.statusMessage = null;
}
public RESTErrorResponseException(final ObjectId oid, final String time, final String name, final String message,
public RESTErrorResponseExeption(final UUID uuid, final String time, final String name, final String message,
final int status, final String statusMessage) {
this.oid = oid;
this.uuid = uuid;
this.time = time;
this.name = name;
this.message = message;
@ -32,7 +31,7 @@ public class RESTErrorResponseException extends Exception {
@Override
public String toString() {
return "RESTErrorResponseExeption [oid=" + this.oid + ", time=" + this.time + ", name=" + this.name
return "RESTErrorResponseExeption [uuid=" + this.uuid + ", time=" + this.time + ", name=" + this.name
+ ", message=" + this.message + ", status=" + this.status + ", statusMessage=" + this.statusMessage
+ "]";
}

View File

@ -71,25 +71,4 @@ public class AnalyzeApi {
}
return out;
}
public void displayAllApi() {
LOGGER.info("List all API:");
for (final ApiGroupModel model : getAllApi()) {
LOGGER.info(" - {}: {}", model.name, model.getClass().getCanonicalName());
}
}
public void displayAllModel() {
LOGGER.info("List all Model:");
for (final ClassModel model : getAllModel()) {
final StringBuilder out = new StringBuilder();
for (final ClassModel classModel : model.getAlls()) {
out.append(classModel.getOriginClasses().getCanonicalName());
out.append(",");
}
LOGGER.info(" - {}", out.toString());
}
}
}

View File

@ -1,232 +0,0 @@
package org.kar.archidata.externalRestApi;
import java.io.FileWriter;
import java.io.InputStream;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.ContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.catcher.RestErrorResponse;
import org.kar.archidata.externalRestApi.dot.DotApiGeneration;
import org.kar.archidata.externalRestApi.dot.DotClassElement;
import org.kar.archidata.externalRestApi.dot.DotClassElement.DefinedPosition;
import org.kar.archidata.externalRestApi.dot.DotClassElementGroup;
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
public class DotGenerateApi {
public static void generateApi(final AnalyzeApi api, final String pathDotFile) throws Exception {
final List<DotClassElement> localModel = generateApiModel(api);
final DotClassElementGroup dotGroup = new DotClassElementGroup(localModel);
try (final FileWriter myWriter = new FileWriter(pathDotFile)) {
myWriter.write("""
# Architecture auto-generated file
digraph UML_Class_diagram {
#rankdir=NS;
graph [
pad="0.5"
nodesep="1"
#ranksep="2"
label="Rest API server Model"
labelloc="t"
fontname="FreeMono,Sans-Mono,Helvetica,Arial,sans-serif"
]
node [
fontname="FreeMono,Sans-Mono,Helvetica,Arial,sans-serif"
shape=record
style=filled
fillcolor=gray95
]
edge [fontname="FreeMono,Sans-Mono,Helvetica,Arial,sans-serif"]
""");
/*
myWriter.write("""
subgraph REST_API {
style=filled;
color=lightgrey;
label="REST API";
rankdir=LR;
""");
*/
for (final ApiGroupModel element : api.apiModels) {
final String tmp = DotApiGeneration.generateApiFile(element, dotGroup);
myWriter.write(tmp);
myWriter.write("\n");
}
// create an invisible link to force all element to be link together:
if (false) {
String previous = null;
for (final ApiGroupModel element : api.apiModels) {
if (previous == null) {
previous = element.name;
continue;
}
myWriter.write("\t{ ");
myWriter.write(previous);
myWriter.write(":s -> ");
previous = element.name;
myWriter.write(previous);
myWriter.write(":n [style=invis]}\n");
}
}
/*
myWriter.write("""
}
""");
myWriter.write("""
subgraph Models {
style=filled;
color=lightgrey;
label="Models";
rankdir=NS;
""");
*/
// Generates all MODEL files
for (final DotClassElement element : localModel) {
final String tmp = element.generateFile(dotGroup);
myWriter.write(tmp);
myWriter.write("\n");
}
/*
myWriter.write("""
}
""");
*/
myWriter.write("""
}
""");
}
}
private static List<DotClassElement> generateApiModel(final AnalyzeApi api) throws Exception {
// First step is to add all specific basic elements the wrap correctly the model
final List<DotClassElement> dotModels = new ArrayList<>();
List<ClassModel> models = api.getCompatibleModels(List.of(Void.class, void.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "void", "void", null, null, DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(Object.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Object", "object", null, "Object", DefinedPosition.NATIVE));
}
// Map is binded to any ==> can not determine this complex model for now
models = api.getCompatibleModels(List.of(Map.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Object", "any", null, null, DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(String.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "String", "string", null, "String", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(
List.of(InputStream.class, FormDataContentDisposition.class, ContentDisposition.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "File", "File", null, "File", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(Boolean.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Boolean", "boolean", null, "Boolean", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(boolean.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "boolean", "boolean", null, "boolean", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(UUID.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "UUID", "UUID", "isUUID", "UUID", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(long.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "long", "Long", "isLong", "long", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Long.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Long", "Long", "isLong", "Long", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(short.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "short", "Short", "isShort", "short", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Short.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Short", "Short", "isShort", "Short", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(int.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "int", "Integer", "isInteger", "int", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Integer.class));
if (models != null) {
dotModels.add(
new DotClassElement(models, "Integer", "Integer", "isInteger", "Integer", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(double.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Double", "Double", "isDouble", "double", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Double.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Double", "Double", "isDouble", "Double", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(float.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "float", "Float", "isFloat", "float", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Float.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Float", "Float", "isFloat", "Float", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Instant.class));
if (models != null) {
dotModels.add(
new DotClassElement(models, "Instant", "Instant", "isInstant", "Instant", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Date.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Date", "IsoDate", "isIsoDate", "Date", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Timestamp.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Timestamp", "Timestamp", "isTimestamp", "Timestamp",
DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(LocalDate.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "LocalDate", "LocalDate", "isLocalDate", "LocalDate",
DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(LocalTime.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "LocalTime", "LocalTime", "isLocalTime", "LocalTime",
DefinedPosition.BASIC));
}
// needed for Rest interface
api.addModel(RestErrorResponse.class);
for (final ClassModel model : api.getAllModel()) {
boolean alreadyExist = false;
for (final DotClassElement elem : dotModels) {
if (elem.isCompatible(model)) {
alreadyExist = true;
break;
}
}
if (alreadyExist) {
continue;
}
dotModels.add(new DotClassElement(model));
}
return dotModels;
}
}

View File

@ -17,7 +17,6 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.ContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.catcher.RestErrorResponse;
@ -31,7 +30,7 @@ import org.kar.archidata.externalRestApi.typescript.TsClassElementGroup;
public class TsGenerateApi {
/**
* Generate a full API tree for Typescript in a specific folder.
* This generate a folder containing a full API with "model" folder and "api" folder.
* This generate a folder containing a full API with "model" filder and "api" folder.
* The generation depend of Zod and can be strict compile.
* @param api Data model to generate the api
* @param pathPackage Path to store the api.
@ -119,8 +118,6 @@ public class TsGenerateApi {
}
private static List<TsClassElement> generateApiModel(final AnalyzeApi api) throws Exception {
// needed for Rest interface
api.addModel(RestErrorResponse.class);
// First step is to add all specific basic elements the wrap correctly the model
final List<TsClassElement> tsModels = new ArrayList<>();
List<ClassModel> models = api.getCompatibleModels(List.of(Void.class, void.class));
@ -158,12 +155,6 @@ public class TsGenerateApi {
tsModels.add(new TsClassElement(models, "ZodUUID", "UUID", "isUUID", "zod.string().uuid()",
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));
if (models != null) {
tsModels.add(
@ -214,6 +205,8 @@ public class TsGenerateApi {
tsModels.add(new TsClassElement(models, "ZodLocalTime", "LocalTime", "isLocalTime", "zod.string().time()",
DefinedPosition.BASIC));
}
// needed for Rest interface
api.addModel(RestErrorResponse.class);
for (final ClassModel model : api.getAllModel()) {
boolean alreadyExist = false;
for (final TsClassElement elem : tsModels) {

View File

@ -1,415 +0,0 @@
package org.kar.archidata.externalRestApi.dot;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.kar.archidata.externalRestApi.dot.DotClassElement.DefinedPosition;
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
import org.kar.archidata.externalRestApi.model.ApiModel;
import org.kar.archidata.externalRestApi.model.ApiModel.OptionalClassModel;
import org.kar.archidata.externalRestApi.model.ClassEnumModel;
import org.kar.archidata.externalRestApi.model.ClassListModel;
import org.kar.archidata.externalRestApi.model.ClassMapModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
import org.kar.archidata.externalRestApi.model.ClassObjectModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DotApiGeneration {
static final Logger LOGGER = LoggerFactory.getLogger(DotApiGeneration.class);
public static String generateClassEnumModelTypescript(
final ClassEnumModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
imports.add(model);
final DotClassElement dotModel = dotGroup.find(model);
return dotModel.dotTypeName;
}
public static String generateClassObjectModelTypescript(
final ClassObjectModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType != DefinedPosition.NATIVE) {
imports.add(model);
}
if (dotModel.nativeType != DefinedPosition.NORMAL) {
return dotModel.dotTypeName;
}
return dotModel.dotTypeName;
}
public static String generateClassMapModelTypescript(
final ClassMapModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("Map&lt;");
out.append(generateClassModelTypescript(model.keyModel, dotGroup, imports));
out.append(", ");
out.append(generateClassModelTypescript(model.valueModel, dotGroup, imports));
out.append("&gt;");
return out.toString();
}
public static String generateClassListModelTypescript(
final ClassListModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("List&lt;");
out.append(generateClassModelTypescript(model.valueModel, dotGroup, imports));
out.append("&gt;");
return out.toString();
}
public static String generateClassModelTypescript(
final ClassModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
return generateClassObjectModelTypescript(objectModel, dotGroup, imports);
}
if (model instanceof final ClassListModel listModel) {
return generateClassListModelTypescript(listModel, dotGroup, imports);
}
if (model instanceof final ClassMapModel mapModel) {
return generateClassMapModelTypescript(mapModel, dotGroup, imports);
}
if (model instanceof final ClassEnumModel enumModel) {
return generateClassEnumModelTypescript(enumModel, dotGroup, imports);
}
throw new IOException("Impossible model:" + model);
}
public static String generateClassModelsTypescript(
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 0) {
return "void";
}
final StringBuilder out = new StringBuilder();
if (models.size() > 1) {
out.append("Union&lt;");
}
boolean isFirst = true;
for (final ClassModel model : models) {
if (isFirst) {
isFirst = false;
} else {
out.append(", ");
}
final String data = DotClassElement.generateClassModelTypescript(model, dotGroup);
out.append(data);
}
if (models.size() > 1) {
out.append("&gt;");
}
return out.toString();
}
public static List<String> generateClassModelsLinks(
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 0) {
return null;
}
final List<String> out = new ArrayList<>();
final boolean isFirst = true;
for (final ClassModel model : models) {
final String data = DotClassElement.generateClassModelTypescriptLink(model, dotGroup);
if (data != null) {
out.add(data);
}
}
return out;
}
public static String capitalizeFirstLetter(final String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
public static String generateApiFile(final ApiGroupModel element, final DotClassElementGroup dotGroup)
throws IOException {
final StringBuilder data = new StringBuilder();
final StringBuilder outLinks = new StringBuilder();
data.append("""
%s [
shape=plain
label=<<table color="#FF3333" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td><b>%s</b><br/>(REST)</td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
""".formatted(element.name, element.name));
final Set<ClassModel> imports = new HashSet<>();
final Set<ClassModel> zodImports = new HashSet<>();
final Set<ClassModel> isImports = new HashSet<>();
final Set<ClassModel> writeImports = new HashSet<>();
final Set<String> toolImports = new HashSet<>();
for (final ApiModel interfaceElement : element.interfaces) {
final List<String> consumes = interfaceElement.consumes;
final List<String> produces = interfaceElement.produces;
final boolean needGenerateProgress = interfaceElement.needGenerateProgress;
/*
if (returnComplexModel != null) {
data.append(returnComplexModel.replaceAll("(?m)^", "\t"));
for (final ClassModel elem : interfaceElement.returnTypes) {
zodImports.addAll(elem.getDependencyGroupModels());
}
}
*/
data.append("\t\t\t\t\t<tr><td align=\"left\" port=\"");
data.append(interfaceElement.name);
data.append("\"><b> + ");
data.append(interfaceElement.name);
data.append("(");
boolean hasParam = false;
/*
if (!interfaceElement.queries.isEmpty()) {
data.append("\n\t\tqueries: {");
for (final Entry<String, List<ClassModel>> queryEntry : interfaceElement.queries.entrySet()) {
data.append("\n\t\t\t");
data.append(queryEntry.getKey());
data.append("?: ");
data.append(generateClassModelsTypescript(queryEntry.getValue(), dotGroup, imports, false));
data.append(",");
}
data.append("\n\t\t},");
}
*/
/* fonctionnel mais trop de donnée
if (!interfaceElement.parameters.isEmpty()) {
//data.append("params: {");
for (final Entry<String, List<ClassModel>> paramEntry : interfaceElement.parameters.entrySet()) {
data.append("");
data.append(paramEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(paramEntry.getValue(), dotGroup, imports, false));
data.append(",");
}
//data.append("},");
}
*/
if (interfaceElement.unnamedElement.size() == 1) {
if (hasParam) {
data.append(", ");
}
hasParam = true;
data.append("data: ");
data.append(
generateClassModelTypescript(interfaceElement.unnamedElement.get(0), dotGroup, writeImports));
} else if (interfaceElement.multiPartParameters.size() != 0) {
if (hasParam) {
data.append(", ");
}
hasParam = true;
boolean hasParam2 = false;
data.append("data: {");
for (final Entry<String, OptionalClassModel> pathEntry : interfaceElement.multiPartParameters
.entrySet()) {
if (hasParam2) {
data.append(", ");
}
hasParam2 = true;
data.append(pathEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(pathEntry.getValue().model(), dotGroup));
}
data.append("}");
}
data.append("): ");
/*
String tmp = DotClassElement.generateLocalModel(
final String ModelName,
final List<ClassModel> models,
final DotClassElementGroup dotGroup)
public static String generateClassModelsTypescript(
final List<ClassModel> models,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
*/
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, dotGroup);
data.append(returnType);
final List<String> returnLinks = generateClassModelsLinks(interfaceElement.returnTypes, dotGroup);
for (final String link : returnLinks) {
outLinks.append("\t");
outLinks.append(element.name);
outLinks.append(":");
outLinks.append(interfaceElement.name);
outLinks.append(":e -> ");
outLinks.append(link);
outLinks.append(":NAME:w\n");
}
data.append("</b>");
//data.append("<br align=\"left\"/>&nbsp;&nbsp;&nbsp;&nbsp;");
data.append("</td></tr>\n\t\t\t\t\t\t\t<tr><td align=\"left\"> ");
/*
data.append("\n\t\t\trestModel: {");
data.append("\n\t\t\t\tendPoint: \"");
*/
data.append(interfaceElement.restEndPoint);
/*
data.append("\",");
data.append("\n\t\t\t\trequestType: HTTPRequestModel.");
toolImports.add("HTTPRequestModel");
data.append(interfaceElement.restTypeRequest);
data.append(",");
if (consumes != null) {
for (final String elem : consumes) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.JSON,");
toolImports.add("HTTPMimeType");
break;
} else if (MediaType.MULTIPART_FORM_DATA.equals(elem)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.MULTIPART,");
toolImports.add("HTTPMimeType");
break;
} else if (MediaType.TEXT_PLAIN.equals(elem)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,");
toolImports.add("HTTPMimeType");
break;
}
}
} else if (RestTypeRequest.DELETE.equals(interfaceElement.restTypeRequest)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,");
toolImports.add("HTTPMimeType");
}
if (produces != null) {
if (produces.size() > 1) {
data.append("\n\t\t\t\taccept: produce,");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, dotGroup,
imports, false);
if (!"void".equals(returnType)) {
for (final String elem : produces) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
data.append("\n\t\t\t\taccept: HTTPMimeType.JSON,");
toolImports.add("HTTPMimeType");
break;
}
}
}
}
}
data.append("\n\t\t\t},");
data.append("\n\t\t\trestConfig,");
if (!interfaceElement.parameters.isEmpty()) {
data.append("\n\t\t\tparams,");
}
if (!interfaceElement.queries.isEmpty()) {
data.append("\n\t\t\tqueries,");
}
if (interfaceElement.unnamedElement.size() == 1) {
data.append("\n\t\t\tdata,");
} else if (interfaceElement.multiPartParameters.size() != 0) {
data.append("\n\t\t\tdata,");
}
if (needGenerateProgress) {
data.append("\n\t\t\tcallback,");
}
data.append("\n\t\t}");
if (returnComplexModel != null) {
data.append(", is");
data.append(returnModelNameIfComplex);
} else {
final DotClassElement retType = dotGroup.find(interfaceElement.returnTypes.get(0));
if (retType.dotCheckType != null) {
data.append(", ");
data.append(retType.dotCheckType);
imports.add(interfaceElement.returnTypes.get(0));
}
}
*/
data.append("</td></tr>\n");
}
/*
data.append("\n}\n");
final StringBuilder out = new StringBuilder();
final List<String> toolImportsList = new ArrayList<>(toolImports);
Collections.sort(toolImportsList);
if (toolImportsList.size() != 0) {
out.append("import {");
for (final String elem : toolImportsList) {
out.append("\n\t");
out.append(elem);
out.append(",");
}
out.append("\n} from \"../rest-tools\";\n\n");
}
if (zodImports.size() != 0) {
out.append("import { z as zod } from \"zod\"\n");
}
final Set<String> finalImportSet = new TreeSet<>();
for (final ClassModel model : imports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add(dotModel.dotTypeName);
}
for (final ClassModel model : isImports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
if (dotModel.dotCheckType != null) {
finalImportSet.add(dotModel.dotCheckType);
}
}
for (final ClassModel model : zodImports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add("Zod" + dotModel.dotTypeName);
}
for (final ClassModel model : writeImports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add(dotModel.dotTypeName + "Write");
}
if (finalImportSet.size() != 0) {
out.append("import {");
for (final String elem : finalImportSet) {
out.append("\n\t");
out.append(elem);
out.append(",");
}
out.append("\n} from \"../model\";\n\n");
}
out.append(data.toString());
*/
data.append("""
</table>
</td>
</tr>
</table>>
]
""");
data.append(outLinks.toString());
return data.toString();
}
}

View File

@ -1,485 +0,0 @@
package org.kar.archidata.externalRestApi.dot;
import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;
import org.kar.archidata.externalRestApi.model.ClassEnumModel;
import org.kar.archidata.externalRestApi.model.ClassListModel;
import org.kar.archidata.externalRestApi.model.ClassMapModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
import org.kar.archidata.externalRestApi.model.ClassObjectModel;
import org.kar.archidata.externalRestApi.model.ClassObjectModel.FieldProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DotClassElement {
static final Logger LOGGER = LoggerFactory.getLogger(DotClassElement.class);
public enum DefinedPosition {
NATIVE, // Native element of dot language.
BASIC, // basic wrapping for JAVA type.
NORMAL // Normal Object to interpret.
}
public List<ClassModel> models;
public String zodName;
public String dotTypeName;
public String dotCheckType;
public String declaration;
public String fileName = null;
public String comment = null;
public DefinedPosition nativeType = DefinedPosition.NORMAL;
public static String determineFileName(final String className) {
return className.replaceAll("([a-z])([A-Z])", "$1-$2").replaceAll("([A-Z])([A-Z][a-z])", "$1-$2").toLowerCase();
}
public DotClassElement(final List<ClassModel> model, final String zodName, final String dotTypeName,
final String dotCheckType, final String declaration, final DefinedPosition nativeType) {
this.models = model;
this.zodName = zodName;
this.dotTypeName = dotTypeName;
this.declaration = declaration;
this.nativeType = nativeType;
}
public DotClassElement(final ClassModel model) {
this.models = List.of(model);
this.dotTypeName = model.getOriginClasses().getSimpleName();
this.declaration = null;
}
public boolean isCompatible(final ClassModel model) {
return this.models.contains(model);
}
public String generateEnum(final ClassEnumModel model, final DotClassElementGroup dotGroup) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("""
%s [
shape=plain
label=<<table color="#33FF33" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td port="NAME"><b>%s</b><br/>(ENUM)</td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
""".formatted(this.dotTypeName, this.dotTypeName));
final boolean first = true;
for (final Entry<String, Object> elem : model.getListOfValues().entrySet()) {
out.append("\t\t\t\t\t\t<tr><td align=\"left\"><b> + ");
out.append(elem.getKey());
out.append("</b> = ");
if (elem.getValue() instanceof final Integer value) {
out.append(value);
} else {
out.append("'");
out.append(elem.getValue());
out.append("'");
}
out.append("</td></tr>\n");
}
out.append("""
</table>
</td>
</tr>
</table>>
]
""");
return out.toString();
}
public String generateImporDot(final List<ClassModel> depModels, final DotClassElementGroup dotGroup)
throws IOException {
final StringBuilder out = new StringBuilder();
for (final ClassModel depModel : depModels) {
final DotClassElement dotModel = dotGroup.find(depModel);
if (dotModel.nativeType != DefinedPosition.NATIVE) {
out.append("import {");
out.append(dotModel.zodName);
out.append("} from \"./");
out.append(dotModel.fileName);
out.append("\";\n");
}
}
return out.toString();
}
private Object generateComment(final ClassObjectModel model) {
final StringBuilder out = new StringBuilder();
if (model.getDescription() != null || model.getExample() != null) {
out.append("/**\n");
if (model.getDescription() != null) {
for (final String elem : model.getDescription().split("\n")) {
out.append(" * ");
out.append(elem);
out.append("\n");
}
}
if (model.getExample() != null) {
out.append(" * Example:\n");
out.append(" * ```\n");
for (final String elem : model.getExample().split("\n")) {
out.append(" * ");
out.append(elem);
out.append("\n");
}
out.append(" * ```\n");
}
out.append(" */\n");
}
return out.toString();
}
public String optionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (field.nullable()) {
return ".optional()";
}
if (field.notNull()) {
return "";
}
// Other object:
if (field.model().getOriginClasses() == null || field.model().getOriginClasses().isPrimitive()) {
return "";
}
if (field.columnNotNull()) {
return "";
}
return ".optional()";
}
public String maxSizeZod(final FieldProperty field) {
final StringBuilder builder = new StringBuilder();
final Class<?> clazz = field.model().getOriginClasses();
if (clazz == String.class) {
if (field.sizeMin() > 0) {
builder.append(".min(");
builder.append(field.sizeMin());
builder.append(")");
}
if (field.sizeMax() > 0) {
builder.append(".max(");
builder.append(field.sizeMax());
builder.append(")");
}
}
if (clazz == short.class || clazz == Short.class || clazz == int.class || clazz == Integer.class
|| clazz == long.class || clazz == Long.class || clazz == float.class || clazz == Float.class
|| clazz == double.class || clazz == Double.class) {
if (field.min() != null && field.min() > 0) {
builder.append(".min(");
builder.append(field.min());
builder.append(")");
}
if (field.max() != null && field.max() > 0) {
builder.append(".max(");
builder.append(field.max());
builder.append(")");
}
}
return builder.toString();
}
public String readOnlyZod(final FieldProperty field) {
if (field.readOnly()) {
return ".readonly()";
}
return "";
}
public String generateBaseObject() {
final StringBuilder out = new StringBuilder();
return out.toString();
}
public String convertHtml(final String data) {
return data.replace("<", "&lt;").replace(">", "&gt;");
}
public static String generateClassModelTypescript(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof final ClassListModel fieldListModel) {
return generateDotList(fieldListModel, dotGroup);
} else if (model instanceof final ClassMapModel fieldMapModel) {
return generateDotMap(fieldMapModel, dotGroup);
}
throw new IOException("Impossible model:" + model);
}
public static String generateClassModelTypescriptLink(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
if (dotFieldModel.nativeType == DefinedPosition.NORMAL) {
return dotFieldModel.dotTypeName;
}
} else if (model instanceof final ClassListModel fieldListModel) {
final String className = generateDotListClassName(fieldListModel, dotGroup);
if (className != null) {
return className;
}
} else if (model instanceof final ClassMapModel fieldMapModel) {
final String className = generateDotMapClassName(fieldMapModel, dotGroup);
if (className != null) {
return className;
}
}
return null;
}
public String generateObject(final ClassObjectModel model, final DotClassElementGroup dotGroup) throws IOException {
final StringBuilder out = new StringBuilder();
final StringBuilder outLinks = new StringBuilder();
out.append("""
%s [
shape=plain
ranksep="2"
label=<<table color="#000000" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td port="NAME"><b>%s</b></td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
""".formatted(this.dotTypeName, this.dotTypeName));
String inheritence = null;
if (model.getExtendsClass() != null) {
final ClassModel parentClass = model.getExtendsClass();
final DotClassElement dotParentModel = dotGroup.find(parentClass);
inheritence = dotParentModel.dotTypeName;
}
if (model.getFields().size() == 0) {
out.append("\t\t\t\t\t\t<tr><td> <i>(empty)</i> </td></tr>");
}
for (final FieldProperty field : model.getFields()) {
final ClassModel fieldModel = field.model();
if (field.comment() != null) {
out.append("\t\t\t\t\t\t<tr><td align=\"left\"><i> // ");
out.append(convertHtml(field.comment()));
out.append("</i></td></tr>\n");
}
out.append("\t\t\t\t\t\t<tr><td align=\"left\" port=\"");
out.append(field.name());
out.append("\"><b> + ");
out.append(field.name());
out.append("</b>: ");
out.append(generateClassModelTypescript(fieldModel, dotGroup));
final String remoteType = generateClassModelTypescriptLink(fieldModel, dotGroup);
if (remoteType != null) {
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(remoteType);
outLinks.append(":NAME:w\n");
} else if (field.linkClass() != null) {
final String remoteLinkType = generateClassModelTypescriptLink(field.linkClass(), dotGroup);
if (remoteLinkType != null) {
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(remoteLinkType);
outLinks.append(":NAME:w\n");
}
}
out.append("</td></tr>\n");
}
out.append("""
</table>
</td>
</tr>
</table>>
]
""");
if (inheritence != null) {
out.append("\tedge [dir=back arrowtail=empty arrowsize=2]\n");
out.append("\t");
out.append(inheritence);
// heritage stop link on the "s" South
out.append(":s -> ");
out.append(this.dotTypeName);
// heritage start link on the "n" North
out.append(":n\n");
}
if (!outLinks.isEmpty()) {
out.append("\tedge [dir=back arrowtail=diamond arrowsize=2]\n");
//out.append("\tedge [arrowhead=diamond arrowsize=2]\n");
out.append(outLinks.toString());
}
return out.toString();
}
private static String generateDotMap(final ClassMapModel model, final DotClassElementGroup dotGroup) {
final StringBuilder out = new StringBuilder();
out.append("Map&lt;");
if (model.keyModel instanceof final ClassListModel fieldListModel) {
final String tmp = generateDotList(fieldListModel, dotGroup);
out.append(tmp);
} else if (model.keyModel instanceof final ClassMapModel fieldMapModel) {
final String tmp = generateDotMap(fieldMapModel, dotGroup);
out.append(tmp);
} else if (model.keyModel instanceof final ClassObjectModel fieldObjectModel) {
final String tmp = generateDotObject(fieldObjectModel, dotGroup);
out.append(tmp);
} else if (model.keyModel instanceof final ClassEnumModel fieldEnumModel) {
final String tmp = generateDotEnum(fieldEnumModel, dotGroup);
out.append(tmp);
}
out.append(", ");
if (model.valueModel instanceof final ClassListModel fieldListModel) {
final String tmp = generateDotList(fieldListModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
final String tmp = generateDotMap(fieldMapModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
final String tmp = generateDotObject(fieldObjectModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassEnumModel fieldEnumModel) {
final String tmp = generateDotEnum(fieldEnumModel, dotGroup);
out.append(tmp);
}
out.append("&gt;");
return out.toString();
}
private static String generateDotEnum(final ClassEnumModel model, final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
return dotParentModel.dotTypeName;
}
private static String generateDotObject(final ClassObjectModel model, final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
return dotParentModel.dotTypeName;
}
private static String generateDotObjectClassName(
final ClassObjectModel model,
final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
if (dotParentModel.nativeType == DefinedPosition.NORMAL) {
return dotParentModel.dotTypeName;
}
return null;
}
private static String generateDotListClassName(final ClassListModel model, final DotClassElementGroup dotGroup) {
if (model.valueModel instanceof final ClassListModel fieldListModel) {
return generateDotListClassName(fieldListModel, dotGroup);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
return generateDotMapClassName(fieldMapModel, dotGroup);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
return generateDotObjectClassName(fieldObjectModel, dotGroup);
}
return null;
}
private static String generateDotMapClassName(final ClassMapModel model, final DotClassElementGroup dotGroup) {
if (model.valueModel instanceof final ClassListModel fieldListModel) {
return generateDotListClassName(fieldListModel, dotGroup);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
return generateDotMapClassName(fieldMapModel, dotGroup);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
return generateDotObjectClassName(fieldObjectModel, dotGroup);
} else if (model.valueModel instanceof final ClassEnumModel fieldEnumModel) {
return generateDotEnum(fieldEnumModel, dotGroup);
}
return null;
}
private static String generateDotList(final ClassListModel model, final DotClassElementGroup dotGroup) {
final StringBuilder out = new StringBuilder();
out.append("List&lt;");
if (model.valueModel instanceof final ClassListModel fieldListModel) {
final String tmp = generateDotList(fieldListModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
final String tmp = generateDotMap(fieldMapModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
final String tmp = generateDotObject(fieldObjectModel, dotGroup);
out.append(tmp);
}
out.append("&gt;");
return out.toString();
}
public String generateFile(final DotClassElementGroup dotGroup) throws IOException {
if (this.nativeType == DefinedPosition.NATIVE) {
return "";
}
final ClassModel model = this.models.get(0);
String data = "";
if (this.nativeType == DefinedPosition.BASIC && model instanceof ClassObjectModel) {
// nothing to do___ data = generateBaseObject();
} else if (model instanceof final ClassEnumModel modelEnum) {
data = generateEnum(modelEnum, dotGroup);
} else if (model instanceof final ClassObjectModel modelObject) {
data = generateObject(modelObject, dotGroup);
}
return data;
}
private static String generateLocalModelBase(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
return generateDotObject(objectModel, dotGroup);
}
if (model instanceof final ClassEnumModel enumModel) {
return generateDotEnum(enumModel, dotGroup);
}
if (model instanceof final ClassListModel listModel) {
return generateDotList(listModel, dotGroup);
}
if (model instanceof final ClassMapModel mapModel) {
return generateDotMap(mapModel, dotGroup);
}
return "";
}
public static String generateLocalModel(
final String ModelName,
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 1) {
if (models.get(0) instanceof ClassObjectModel) {
return null;
}
if (models.get(0) instanceof ClassEnumModel) {
return null;
}
}
final StringBuilder out = new StringBuilder();
if (models.size() == 1) {
out.append(generateLocalModelBase(models.get(0), dotGroup));
} else {
out.append("Union&lt;");
for (final ClassModel model : models) {
out.append("\t");
out.append(generateLocalModelBase(models.get(0), dotGroup));
out.append(",\n");
}
out.append("&gt;");
}
return out.toString();
}
}

View File

@ -1,27 +0,0 @@
package org.kar.archidata.externalRestApi.dot;
import java.util.List;
import org.kar.archidata.externalRestApi.model.ClassModel;
public class DotClassElementGroup {
private final List<DotClassElement> dotElements;
public List<DotClassElement> getDotElements() {
return this.dotElements;
}
public DotClassElementGroup(final List<DotClassElement> tsElements) {
this.dotElements = tsElements;
}
public DotClassElement find(final ClassModel model) {
for (final DotClassElement elem : this.dotElements) {
if (elem.isCompatible(model)) {
return elem;
}
}
return null;
}
}

View File

@ -15,10 +15,6 @@ import org.slf4j.LoggerFactory;
public class ApiModel {
static final Logger LOGGER = LoggerFactory.getLogger(ApiModel.class);
public record OptionalClassModel(
List<ClassModel> model,
boolean optional) {}
Class<?> originClass;
Method orignMethod;
@ -40,7 +36,7 @@ public class ApiModel {
// list of all query (?key...)
public final Map<String, List<ClassModel>> queries = new HashMap<>();
// when request multi-part, need to separate it.
public final Map<String, OptionalClassModel> multiPartParameters = new HashMap<>();
public final Map<String, List<ClassModel>> multiPartParameters = new HashMap<>();
// model of data available
public final List<ClassModel> unnamedElement = new ArrayList<>();
@ -157,7 +153,6 @@ public class ApiModel {
final String pathParam = ApiTool.apiAnnotationGetPathParam(parameter);
final String queryParam = ApiTool.apiAnnotationGetQueryParam(parameter);
final String formDataParam = ApiTool.apiAnnotationGetFormDataParam(parameter);
final boolean formDataParamOptional = ApiTool.apiAnnotationGetFormDataOptional(parameter);
if (queryParam != null) {
if (!this.queries.containsKey(queryParam)) {
this.queries.put(queryParam, parameterModel);
@ -168,8 +163,7 @@ public class ApiModel {
}
} else if (formDataParam != null) {
if (!this.multiPartParameters.containsKey(formDataParam)) {
this.multiPartParameters.put(formDataParam,
new OptionalClassModel(parameterModel, formDataParamOptional));
this.multiPartParameters.put(formDataParam, parameterModel);
}
} else {
this.unnamedElement.addAll(parameterModel);

View File

@ -7,10 +7,7 @@ import java.util.Arrays;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.ARCHIVE;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.FormDataOptional;
import org.kar.archidata.annotation.RESTORE;
import org.kar.archidata.annotation.TypeScriptProgress;
import io.swagger.v3.oas.annotations.Operation;
@ -109,12 +106,6 @@ public class ApiTool {
if (element.getDeclaredAnnotationsByType(DELETE.class).length == 1) {
return "DELETE";
}
if (element.getDeclaredAnnotationsByType(RESTORE.class).length == 1) {
return "RESTORE";
}
if (element.getDeclaredAnnotationsByType(ARCHIVE.class).length == 1) {
return "ARCHIVE";
}
return null;
}
@ -134,12 +125,6 @@ public class ApiTool {
if (element.getDeclaredAnnotationsByType(DELETE.class).length == 1) {
return RestTypeRequest.DELETE;
}
if (element.getDeclaredAnnotationsByType(RESTORE.class).length == 1) {
return RestTypeRequest.RESTORE;
}
if (element.getDeclaredAnnotationsByType(ARCHIVE.class).length == 1) {
return RestTypeRequest.ARCHIVE;
}
return null;
}
@ -159,14 +144,6 @@ public class ApiTool {
return ((QueryParam) annotation[0]).value();
}
public static boolean apiAnnotationGetFormDataOptional(final Parameter element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(FormDataOptional.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static String apiAnnotationGetFormDataParam(final Parameter element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(FormDataParam.class);
if (annotation.length == 0) {

View File

@ -10,7 +10,6 @@ public class ClassEnumModel extends ClassModel {
protected ClassEnumModel(final Class<?> clazz) {
this.originClasses = clazz;
this.noWriteSpecificMode = true;
}
@Override

View File

@ -11,17 +11,12 @@ import java.util.Set;
public abstract class ClassModel {
protected boolean analyzeDone = false;
protected Class<?> originClasses = null;
protected boolean noWriteSpecificMode = false;
protected List<ClassModel> dependencyModels = new ArrayList<>();
public Class<?> getOriginClasses() {
return this.originClasses;
}
public boolean isNoWriteSpecificMode() {
return this.noWriteSpecificMode;
}
protected boolean isCompatible(final Class<?> clazz) {
return this.originClasses == clazz;
}

View File

@ -1,6 +1,5 @@
package org.kar.archidata.externalRestApi.model;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.LocalDate;
@ -11,15 +10,9 @@ import java.util.List;
import java.util.Set;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.validation.constraints.Size;
public class ClassObjectModel extends ClassModel {
static final Logger LOGGER = LoggerFactory.getLogger(ClassObjectModel.class);
@ -44,7 +37,7 @@ public class ClassObjectModel extends ClassModel {
for (final Field field : superClass.getFields()) {
String name;
try {
name = AnnotationTools.getFieldNameRaw(field);
name = AnnotationTools.getFieldName(field);
if (filedName.equals(name)) {
return true;
}
@ -59,28 +52,19 @@ public class ClassObjectModel extends ClassModel {
public record FieldProperty(
String name,
ClassModel model,
ClassModel linkClass, // link class when use remote ID (ex: list<UUID>)
String comment,
int sizeMin, // String SizeMin
int sizeMax, // String SizeMax
Long min, // number min value
Long max, // number max value
int limitSize,
Boolean readOnly,
Boolean notNull,
Boolean columnNotNull,
Boolean nullable) {
public FieldProperty(final String name, final ClassModel model, final ClassModel linkClass,
final String comment, final int sizeMin, final int sizeMax, final Long min, final Long max,
public FieldProperty(final String name, final ClassModel model, final String comment, final int limitSize,
final Boolean readOnly, final Boolean notNull, final Boolean columnNotNull, final Boolean nullable) {
this.name = name;
this.model = model;
this.linkClass = linkClass;
this.comment = comment;
this.sizeMin = sizeMin;
this.sizeMax = sizeMax;
this.min = min;
this.max = max;
this.limitSize = limitSize;
this.readOnly = readOnly;
this.notNull = notNull;
this.columnNotNull = columnNotNull;
@ -88,59 +72,11 @@ public class ClassObjectModel extends ClassModel {
}
private static int getStringMinSize(final Field field) throws DataAccessException {
final Size size = AnnotationTools.getConstraintsSize(field);
return size != null ? size.min() : 0;
}
private static int getStringMaxSize(final Field field) throws DataAccessException {
final Size size = AnnotationTools.getConstraintsSize(field);
final int colomnLimitSize = AnnotationTools.getLimitSize(field);
return size == null ? colomnLimitSize : colomnLimitSize < size.max() ? colomnLimitSize : size.max();
}
private static Class<?> getSubModelIfExist2(final Field field) {
final ManyToOne manyToOne = AnnotationTools.getManyToOne(field);
if (manyToOne != null) {
if (manyToOne.targetEntity() != null && manyToOne.targetEntity() != void.class) {
return manyToOne.targetEntity();
}
return null;
}
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
if (manyToMany != null) {
if (manyToMany.targetEntity() != null && manyToMany.targetEntity() != void.class) {
return manyToMany.targetEntity();
}
return null;
}
final OneToMany oneToMany = AnnotationTools.getOneToMany(field);
if (oneToMany != null) {
if (oneToMany.targetEntity() != null && oneToMany.targetEntity() != void.class) {
return oneToMany.targetEntity();
}
return null;
}
return null;
}
private static ClassModel getSubModelIfExist(final Field field, final ModelGroup previous) throws IOException {
final Class<?> tmp = getSubModelIfExist2(field);
if (tmp == null) {
return null;
}
return ClassModel.getModel(tmp, previous);
}
public FieldProperty(final Field field, final ModelGroup previous) throws DataAccessException, IOException {
public FieldProperty(final Field field, final ModelGroup previous) throws Exception {
this(field.getName(), //
ClassModel.getModel(field.getGenericType(), previous), //
getSubModelIfExist(field, previous), //
AnnotationTools.getSchemaDescription(field), //
getStringMinSize(field), //
getStringMaxSize(field), //
AnnotationTools.getConstraintsMin(field), //
AnnotationTools.getConstraintsMax(field), //
AnnotationTools.getComment(field), //
AnnotationTools.getLimitSize(field), //
AnnotationTools.getSchemaReadOnly(field), //
AnnotationTools.getConstraintsNotNull(field), //
AnnotationTools.getColumnNotNull(field), //
@ -187,7 +123,6 @@ public class ClassObjectModel extends ClassModel {
}
this.analyzeDone = true;
final Class<?> clazz = this.originClasses;
this.noWriteSpecificMode = AnnotationTools.getNoWriteSpecificMode(clazz);
this.isPrimitive = clazz.isPrimitive();
if (this.isPrimitive) {
return;
@ -217,7 +152,7 @@ public class ClassObjectModel extends ClassModel {
}
alreadyAdded.add(dataName);
LOGGER.trace(" + '{}'", elem.getName());
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldNameRaw(elem), elem.getType());
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType());
final FieldProperty porperty = new FieldProperty(elem, previous);
for (final ClassModel depModel : porperty.model().getAlls()) {
if (!this.dependencyModels.contains(depModel)) {

View File

@ -1,5 +1,5 @@
package org.kar.archidata.externalRestApi.model;
public enum RestTypeRequest {
GET, POST, PUT, PATCH, DELETE, RESTORE, ARCHIVE
GET, POST, PUT, PATCH, DELETE
}

View File

@ -3,9 +3,6 @@ package org.kar.archidata.externalRestApi.typescript;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@ -17,7 +14,6 @@ import java.util.TreeSet;
import org.kar.archidata.dataAccess.DataExport;
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
import org.kar.archidata.externalRestApi.model.ApiModel;
import org.kar.archidata.externalRestApi.model.ApiModel.OptionalClassModel;
import org.kar.archidata.externalRestApi.model.ClassEnumModel;
import org.kar.archidata.externalRestApi.model.ClassListModel;
import org.kar.archidata.externalRestApi.model.ClassMapModel;
@ -45,7 +41,7 @@ public class TsApiGeneration {
final ClassEnumModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final Set<ClassModel> importWrite) throws IOException {
final boolean writeMode) throws IOException {
imports.add(model);
final TsClassElement tsModel = tsGroup.find(model);
return tsModel.tsTypeName;
@ -55,19 +51,15 @@ public class TsApiGeneration {
final ClassObjectModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final Set<ClassModel> importWrite) throws IOException {
final boolean writeMode) throws IOException {
final TsClassElement tsModel = tsGroup.find(model);
if (tsModel.nativeType != DefinedPosition.NATIVE) {
if (importWrite == null || tsModel.models.get(0).isNoWriteSpecificMode()) {
imports.add(model);
} else {
importWrite.add(model);
}
imports.add(model);
}
if (tsModel.nativeType != DefinedPosition.NORMAL) {
return tsModel.tsTypeName;
}
if (importWrite != null && !tsModel.models.get(0).isNoWriteSpecificMode()) {
if (writeMode) {
return tsModel.tsTypeName + "Write";
}
return tsModel.tsTypeName;
@ -77,12 +69,12 @@ public class TsApiGeneration {
final ClassMapModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final Set<ClassModel> importWrite) throws IOException {
final boolean writeMode) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("{[key: ");
out.append(generateClassModelTypescript(model.keyModel, tsGroup, imports, importWrite));
out.append(generateClassModelTypescript(model.keyModel, tsGroup, imports, writeMode));
out.append("]: ");
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, importWrite));
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, writeMode));
out.append(";}");
return out.toString();
}
@ -91,9 +83,9 @@ public class TsApiGeneration {
final ClassListModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final Set<ClassModel> importWrite) throws IOException {
final boolean writeMode) throws IOException {
final StringBuilder out = new StringBuilder();
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, importWrite));
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, writeMode));
out.append("[]");
return out.toString();
}
@ -102,18 +94,18 @@ public class TsApiGeneration {
final ClassModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final Set<ClassModel> importWrite) throws IOException {
final boolean writeMode) throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
return generateClassObjectModelTypescript(objectModel, tsGroup, imports, importWrite);
return generateClassObjectModelTypescript(objectModel, tsGroup, imports, writeMode);
}
if (model instanceof final ClassListModel listModel) {
return generateClassListModelTypescript(listModel, tsGroup, imports, importWrite);
return generateClassListModelTypescript(listModel, tsGroup, imports, writeMode);
}
if (model instanceof final ClassMapModel mapModel) {
return generateClassMapModelTypescript(mapModel, tsGroup, imports, importWrite);
return generateClassMapModelTypescript(mapModel, tsGroup, imports, writeMode);
}
if (model instanceof final ClassEnumModel enumModel) {
return generateClassEnumModelTypescript(enumModel, tsGroup, imports, importWrite);
return generateClassEnumModelTypescript(enumModel, tsGroup, imports, writeMode);
}
throw new IOException("Impossible model:" + model);
}
@ -122,7 +114,7 @@ public class TsApiGeneration {
final List<ClassModel> models,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final Set<ClassModel> importWrite) throws IOException {
final boolean writeMode) throws IOException {
if (models.size() == 0) {
return "void";
}
@ -134,7 +126,7 @@ public class TsApiGeneration {
} else {
out.append(" | ");
}
final String data = generateClassModelTypescript(model, tsGroup, imports, importWrite);
final String data = generateClassModelTypescript(model, tsGroup, imports, writeMode);
out.append(data);
}
return out.toString();
@ -196,7 +188,7 @@ public class TsApiGeneration {
data.append("\n\t\t\tdata,");
}
if (needGenerateProgress) {
data.append("\n\t\t\tcallbacks,");
data.append("\n\t\t\tcallback,");
}
data.append("\n\t\t}: {");
data.append("\n\t\trestConfig: RESTConfig,");
@ -207,7 +199,7 @@ public class TsApiGeneration {
data.append("\n\t\t\t");
data.append(queryEntry.getKey());
data.append("?: ");
data.append(generateClassModelsTypescript(queryEntry.getValue(), tsGroup, imports, null));
data.append(generateClassModelsTypescript(queryEntry.getValue(), tsGroup, imports, false));
data.append(",");
}
data.append("\n\t\t},");
@ -218,28 +210,24 @@ public class TsApiGeneration {
data.append("\n\t\t\t");
data.append(paramEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(paramEntry.getValue(), tsGroup, imports, null));
data.append(generateClassModelsTypescript(paramEntry.getValue(), tsGroup, imports, false));
data.append(",");
}
data.append("\n\t\t},");
}
if (interfaceElement.unnamedElement.size() == 1) {
data.append("\n\t\tdata: ");
data.append(generateClassModelTypescript(interfaceElement.unnamedElement.get(0), tsGroup, imports,
writeImports));
data.append(generateClassModelTypescript(interfaceElement.unnamedElement.get(0), tsGroup, writeImports,
true));
data.append(",");
} else if (interfaceElement.multiPartParameters.size() != 0) {
data.append("\n\t\tdata: {");
for (final Entry<String, OptionalClassModel> pathEntry : interfaceElement.multiPartParameters
for (final Entry<String, List<ClassModel>> pathEntry : interfaceElement.multiPartParameters
.entrySet()) {
data.append("\n\t\t\t");
data.append(pathEntry.getKey());
if (pathEntry.getValue().optional()) {
data.append("?");
}
data.append(": ");
data.append(generateClassModelsTypescript(pathEntry.getValue().model(), tsGroup, imports,
writeImports));
data.append(generateClassModelsTypescript(pathEntry.getValue(), tsGroup, writeImports, true));
data.append(",");
}
data.append("\n\t\t},");
@ -276,7 +264,7 @@ public class TsApiGeneration {
data.append(",");
}
if (needGenerateProgress) {
data.append("\n\t\tcallbacks?: RESTCallbacks,");
data.append("\n\t\tcallback?: RESTCallbacks,");
toolImports.add("RESTCallbacks");
}
data.append("\n\t}): Promise<");
@ -287,7 +275,7 @@ public class TsApiGeneration {
toolImports.add("RESTRequestJson");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, tsGroup, imports,
null);
false);
data.append(returnType);
data.append("> {");
if ("void".equals(returnType)) {
@ -332,7 +320,7 @@ public class TsApiGeneration {
data.append("\n\t\t\t\taccept: produce,");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, tsGroup,
imports, null);
imports, false);
if (!"void".equals(returnType)) {
for (final String elem : produces) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
@ -358,7 +346,7 @@ public class TsApiGeneration {
data.append("\n\t\t\tdata,");
}
if (needGenerateProgress) {
data.append("\n\t\t\tcallbacks,");
data.append("\n\t\t\tcallback,");
}
data.append("\n\t\t}");
if (returnComplexModel != null) {
@ -423,10 +411,7 @@ public class TsApiGeneration {
}
for (final ClassModel model : writeImports) {
final TsClassElement tsModel = tsGroup.find(model);
if (tsModel.nativeType != DefinedPosition.NORMAL) {
continue;
}
if (tsModel.models.get(0).isNoWriteSpecificMode()) {
if (tsModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add(tsModel.tsTypeName + "Write");
@ -444,10 +429,6 @@ public class TsApiGeneration {
out.append(data.toString());
final Path path = Paths.get(pathPackage + File.separator + "api");
if (Files.notExists(path)) {
Files.createDirectories(path);
}
final String fileName = TsClassElement.determineFileName(element.name);
final FileWriter myWriter = new FileWriter(
pathPackage + File.separator + "api" + File.separator + fileName + ".ts");

View File

@ -181,18 +181,12 @@ public class TsClassElement {
if (tsModel.nativeType != DefinedPosition.NATIVE) {
out.append("import {");
out.append(tsModel.zodName);
if (tsModel.nativeType == DefinedPosition.NORMAL && !(tsModel.models.get(0).isNoWriteSpecificMode())) {
out.append(", ");
out.append(tsModel.zodName);
out.append("Write ");
}
out.append("} from \"./");
out.append(tsModel.fileName);
out.append("\";\n");
}
}
return out.toString();
}
private Object generateComment(final ClassObjectModel model) {
@ -221,68 +215,31 @@ public class TsClassElement {
return out.toString();
}
public boolean isOptionalTypeZod(final FieldProperty field) {
public String optionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (field.nullable()) {
return true;
return ".optional()";
}
if (field.notNull()) {
return false;
return "";
}
// Other object:
if (field.model().getOriginClasses() == null || field.model().getOriginClasses().isPrimitive()) {
return false;
return "";
}
if (field.columnNotNull()) {
return false;
return "";
}
return true;
}
public String optionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (isOptionalTypeZod(field)) {
return ".optional()";
}
return "";
}
public String optionalWriteTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (isOptionalTypeZod(field)) {
return ".nullable()";
}
return "";
return ".optional()";
}
public String maxSizeZod(final FieldProperty field) {
final StringBuilder builder = new StringBuilder();
final Class<?> clazz = field.model().getOriginClasses();
if (clazz == String.class) {
if (field.sizeMin() > 0) {
builder.append(".min(");
builder.append(field.sizeMin());
builder.append(")");
}
if (field.sizeMax() > 0) {
builder.append(".max(");
builder.append(field.sizeMax());
builder.append(")");
}
}
if (clazz == short.class || clazz == Short.class || clazz == int.class || clazz == Integer.class
|| clazz == long.class || clazz == Long.class || clazz == float.class || clazz == Float.class
|| clazz == double.class || clazz == Double.class) {
if (field.min() != null && field.min() > 0) {
builder.append(".min(");
builder.append(field.min());
builder.append(")");
}
if (field.max() != null && field.max() > 0) {
builder.append(".max(");
builder.append(field.max());
builder.append(")");
}
if (field.limitSize() > 0 && clazz == String.class) {
builder.append(".max(");
builder.append(field.limitSize());
builder.append(")");
}
return builder.toString();
}
@ -313,9 +270,7 @@ public class TsClassElement {
out.append(getBaseHeader());
out.append(generateImports(model.getDependencyModels(), tsGroup));
out.append("\n");
// ------------------------------------------------------------------------
// -- Generate read mode
// ------------------------------------------------------------------------
out.append(generateComment(model));
out.append("export const ");
out.append(this.zodName);
@ -360,85 +315,27 @@ public class TsClassElement {
out.append("\n});\n");
out.append(generateZodInfer(this.tsTypeName, this.zodName));
out.append(generateExportCheckFunctionWrite(""));
// check if we need to generate write mode :
if (!model.isNoWriteSpecificMode()) {
// ------------------------------------------------------------------------
// -- Generate write mode
// ------------------------------------------------------------------------
//out.append(generateComment(model));
out.append("export const ");
out.append(this.zodName);
out.append("Write = ");
if (model.getExtendsClass() != null) {
final ClassModel parentClass = model.getExtendsClass();
final TsClassElement tsParentModel = tsGroup.find(parentClass);
out.append(tsParentModel.zodName);
out.append("Write");
out.append(".extend({");
} else {
out.append("zod.object({");
}
out.append("\n");
for (final FieldProperty field : model.getFields()) {
// remove all readOnly field
if (field.readOnly()) {
continue;
}
final ClassModel fieldModel = field.model();
if (field.comment() != null) {
out.append("\t/**\n");
out.append("\t * ");
out.append(field.comment());
out.append("\n\t */\n");
}
// Generate the Write Type associated.
out.append("\nexport const ");
out.append(this.zodName);
out.append("Write = ");
out.append(this.zodName);
if (omitField.size() != 0) {
out.append(".omit({\n");
for (final String elem : omitField) {
out.append("\t");
out.append(field.name());
out.append(": ");
if (fieldModel instanceof ClassEnumModel || fieldModel instanceof ClassObjectModel) {
final TsClassElement tsFieldModel = tsGroup.find(fieldModel);
out.append(tsFieldModel.zodName);
} else if (fieldModel instanceof final ClassListModel fieldListModel) {
final String data = generateTsList(fieldListModel, tsGroup);
out.append(data);
} else if (fieldModel instanceof final ClassMapModel fieldMapModel) {
final String data = generateTsMap(fieldMapModel, tsGroup);
out.append(data);
}
out.append(maxSizeZod(field));
out.append(optionalWriteTypeZod(field));
// all write field are optional
if (field.model() instanceof final ClassObjectModel plop) {
if (!plop.isPrimitive()) {
out.append(".optional()");
}
} else {
out.append(".optional()");
}
out.append(",\n");
out.append(elem);
out.append(": true,\n");
}
out.append("\n});\n");
out.append(generateZodInfer(this.tsTypeName + "Write", this.zodName + "Write"));
// Check only the input value ==> no need of the output
out.append(generateExportCheckFunctionWrite("Write"));
// Generate the Write Type associated.
/*
out.append("\nexport const ");
out.append(this.zodName);
out.append("Write = ");
out.append(this.zodName);
if (omitField.size() != 0) {
out.append(".omit({\n");
for (final String elem : omitField) {
out.append("\t");
out.append(elem);
out.append(": true,\n");
}
out.append("\n})");
}
out.append(".partial();\n");
*/
out.append("\n})");
}
out.append(".partial();\n");
out.append(generateZodInfer(this.tsTypeName + "Write", this.zodName + "Write"));
// Check only the input value ==> no need of the output
out.append(generateExportCheckFunctionWrite("Write"));
return out.toString();
}

View File

@ -12,7 +12,6 @@ import java.util.Map.Entry;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.catcher.RestErrorResponse;
import org.kar.archidata.exception.SystemException;
import org.kar.archidata.model.UserByToken;
import org.kar.archidata.tools.JWTWrapper;
import org.slf4j.Logger;
@ -24,7 +23,6 @@ import jakarta.annotation.Priority;
import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
@ -44,40 +42,18 @@ public class AuthenticationFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
protected final String applicationName;
protected final String issuer;
public static final String AUTHENTICATION_SCHEME = "Bearer";
public static final String APIKEY = "ApiKey";
public AuthenticationFilter(final String applicationName) {
this.applicationName = applicationName;
this.issuer = "KarAuth";
}
public AuthenticationFilter(final String applicationName, final String issuer) {
this.applicationName = applicationName;
this.issuer = issuer;
}
public String getRequestedPath(final ContainerRequestContext requestContext) {
final Class<?> resourceClass = this.resourceInfo.getResourceClass();
final Method resourceMethod = this.resourceInfo.getResourceMethod();
final String classPath = resourceClass.isAnnotationPresent(Path.class)
? resourceClass.getAnnotation(Path.class).value()
: "";
final String methodPath = resourceMethod.isAnnotationPresent(Path.class)
? resourceMethod.getAnnotation(Path.class).value()
: "";
final String fullPath = (classPath.startsWith("/") ? "" : "/") + classPath
+ (methodPath.startsWith("/") ? "" : "/") + methodPath;
return fullPath;
}
@Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
/* logger.debug("-----------------------------------------------------"); logger.debug("---- Check if have authorization ----");
* logger.debug("-----------------------------------------------------"); logger.debug(" for:{}", requestContext.getUriInfo().getPath()); */
final Method method = this.resourceInfo.getResourceMethod();
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
@ -164,13 +140,12 @@ public class AuthenticationFilter implements ContainerRequestFilter {
final List<String> roles = Arrays.asList(rolesAnnotation.value());
// check if the user have the right:
boolean haveRight = false;
try {
haveRight = checkRight(requestContext, userContext, roles);
} catch (final SystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
for (final String role : roles) {
if (userContext.isUserInRole(role)) {
haveRight = true;
break;
}
}
// Is user valid?
if (!haveRight) {
LOGGER.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
@ -182,18 +157,6 @@ public class AuthenticationFilter implements ContainerRequestFilter {
// logger.debug("Get local user : {} / {}", user, userByToken);
}
protected boolean checkRight(
final ContainerRequestContext requestContext,
final MySecurityContext userContext,
final List<String> roles) throws SystemException {
for (final String role : roles) {
if (userContext.isUserInRole(this.applicationName + "/" + role)) {
return true;
}
}
return false;
}
private boolean isTokenBasedAuthentication(final String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
@ -208,7 +171,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
// The WWW-Authenticate header is sent along with the response
LOGGER.warn("abortWithUnauthorized:");
final RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
requestContext.abortWith(Response.status(ret.status)
.header(HttpHeaders.WWW_AUTHENTICATE,
AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)")
@ -217,7 +180,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
private void abortWithForbidden(final ContainerRequestContext requestContext, final String message) {
final RestErrorResponse ret = new RestErrorResponse(Response.Status.FORBIDDEN, "FORBIDDEN", message);
LOGGER.error("Error OID={}", ret.oid);
LOGGER.error("Error UUID={}", ret.uuid);
requestContext.abortWith(Response.status(ret.status).header(HttpHeaders.WWW_AUTHENTICATE, message).entity(ret)
.type(MediaType.APPLICATION_JSON).build());
}
@ -230,7 +193,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
// must be override to be good implementation
protected UserByToken validateJwtToken(final String authorization) throws Exception {
// logger.debug(" validate token : " + authorization);
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, this.issuer, null);
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
if (ret == null) {
LOGGER.error("The token is not valid: '{}'", authorization);
@ -245,16 +208,13 @@ public class AuthenticationFilter implements ContainerRequestFilter {
user.type = UserByToken.TYPE_USER;
final Object rowRight = ret.getClaim("right");
if (rowRight != null) {
LOGGER.info("Detect right in Authentication Filter: {}", rowRight);
user.right = (Map<String, Map<String, Object>>) ret.getClaim("right");
/*
final Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
if (rights.containsKey(this.applicationName)) {
user.right = rights.get(this.applicationName);
} else {
LOGGER.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName,
rights);
}
*/
}
// logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight);
return user;

View File

@ -16,12 +16,9 @@ public class CORSFilter implements ContainerResponseFilter {
// System.err.println("filter cors ..." + request.toString());
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Range", "bytes");
response.getHeaders().add("access-control-expose-headers", "range");
response.getHeaders().add("Access-Control-Allow-Headers",
"Origin, content-type, Content-type, Accept, Authorization, mime-type, filename, Range");
"Origin, content-type, Content-type, Accept, Authorization, mime-type, filename");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, PATCH, DELETE, ARCHIVE, RESTORE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD");
}
}

View File

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

View File

@ -1,17 +1,13 @@
package org.kar.archidata.filter;
import java.security.Principal;
import java.util.Set;
import org.kar.archidata.model.UserByToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.SecurityContext;
// https://simplapi.wordpress.com/2015/09/19/jersey-jax-rs-securitycontext-in-action/
public class MySecurityContext implements SecurityContext {
private static final Logger LOGGER = LoggerFactory.getLogger(MySecurityContext.class);
class MySecurityContext implements SecurityContext {
private final GenericContext contextPrincipale;
private final String sheme;
@ -26,126 +22,15 @@ public class MySecurityContext implements SecurityContext {
return this.contextPrincipale;
}
public Object getRightOfRoleInGroup(final String group, final String role) {
if (this.contextPrincipale.userByToken != null) {
return this.contextPrincipale.userByToken.getRight(group, role);
}
return null;
}
public Set<String> getGroups() {
if (this.contextPrincipale.userByToken != null) {
return this.contextPrincipale.userByToken.getGroups();
}
return Set.of();
}
public boolean groupExist(final String group) {
if (this.contextPrincipale.userByToken != null) {
return this.contextPrincipale.userByToken.groupExist(group);
}
return false;
}
// Not sure the Long type is definitive.
public Long getUserID() {
if (this.contextPrincipale.userByToken != null) {
return this.contextPrincipale.userByToken.id;
}
return null;
}
public boolean checkRightInGroup(
final String group,
final String role,
final boolean needRead,
final boolean needWrite) {
if ("USER".equals(role)) {
if (groupExist(group)) {
return true;
}
return false;
}
// get associated Roles:
final Object rightPart = getRightOfRoleInGroup(group, role);
LOGGER.info("detect : {}", rightPart);
long dataRight = 0;
if (rightPart instanceof final Long rightPartCasted) {
dataRight = rightPartCasted;
} else if (rightPart instanceof final Integer rightPartCasted) {
dataRight = rightPartCasted;
}
if (dataRight == PartRight.READ_WRITE.getValue()) {
return true;
}
if (!needRead && needWrite && dataRight == PartRight.WRITE.getValue()) {
return true;
}
if (needRead && !needWrite && dataRight == PartRight.READ.getValue()) {
return true;
}
return false;
}
@Override
public boolean isUserInRole(final String role) {
String roleEdit = role;
boolean needRead = false;
boolean needWrite = false;
// Check if the API overwrite the right needed for this API.
if (roleEdit.contains(":")) {
if (roleEdit.endsWith(":w")) {
try {
roleEdit = roleEdit.substring(0, roleEdit.length() - 2);
} catch (final IndexOutOfBoundsException ex) {
LOGGER.error("Fail to extract role of '{}'", role);
ex.printStackTrace();
return false;
}
needWrite = true;
} else if (roleEdit.endsWith(":r")) {
try {
roleEdit = roleEdit.substring(0, roleEdit.length() - 2);
} catch (final IndexOutOfBoundsException ex) {
LOGGER.error("Fail to extract role of '{}'", role);
ex.printStackTrace();
return false;
}
needRead = true;
} else if (roleEdit.endsWith(":rw")) {
try {
roleEdit = roleEdit.substring(0, roleEdit.length() - 3);
} catch (final IndexOutOfBoundsException ex) {
LOGGER.error("Fail to extract role of '{}'", role);
ex.printStackTrace();
return false;
}
needRead = true;
needWrite = true;
} else {
LOGGER.error("Request check right of an unknow right mode: {} (after ':')", roleEdit);
return false;
if (this.contextPrincipale.userByToken != null) {
final Object value = this.contextPrincipale.userByToken.right.get(role);
if (value instanceof final Boolean ret) {
return ret;
}
}
if (roleEdit.contains("/")) {
final String[] elements = roleEdit.split("/");
return checkRightInGroup(elements[0], elements[1], needRead, needWrite);
}
// Special case, if the token is valid, it is an USER ...
if ("USER".equals(roleEdit)) {
return true;
}
return checkRightInGroup("?system?", roleEdit, needRead, needWrite);
}
public Object getRole(final String role) {
LOGGER.info("contextPrincipale={}", this.contextPrincipale);
if (this.contextPrincipale.userByToken != null) {
LOGGER.info("contextPrincipale.userByToken={}", this.contextPrincipale.userByToken);
LOGGER.info("contextPrincipale.userByToken.right={}", this.contextPrincipale.userByToken.right);
return this.contextPrincipale.userByToken.right.get(role);
}
return null;
return false;
}
@Override

View File

@ -1,30 +0,0 @@
package org.kar.archidata.filter;
import com.fasterxml.jackson.annotation.JsonValue;
public enum PartRight {
NONE(0), //
READ(1), //
WRITE(2), //
READ_WRITE(3);
private final int value;
PartRight(final int value) {
this.value = value;
}
@JsonValue
public int getValue() {
return this.value;
}
public static PartRight fromValue(final int value) {
for (final PartRight element : values()) {
if (element.getValue() == value) {
return element;
}
}
throw new IllegalArgumentException("PartRight: Unknown value: " + value);
}
}

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