Compare commits

..

No commits in common. "main" and "v0.25.6" have entirely different histories.

320 changed files with 2083 additions and 6203 deletions

View File

@ -1,10 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry including="**/*.java" kind="src" output="target/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="test/src">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> <classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
@ -15,31 +35,5 @@
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/testResources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/classes" path="src/main">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
</classpath> </classpath>

View File

@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up JDK 21 - name: Set up JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: '21' java-version: '21'
@ -32,4 +32,4 @@ jobs:
# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
- name: Update dependency graph - name: Update dependency graph
uses: advanced-security/maven-dependency-submission-action@aeab9f885293af501bae8bdfe88c589528ea5e25 uses: advanced-security/maven-dependency-submission-action@4f64ddab9d742a4806eeb588d238e4c311a8397d

128
pom.xml
View File

@ -1,33 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.atria-soft</groupId> <groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.29.0</version> <version>0.25.6</version>
<description>Wrapper to manage a simple interface for REST project to bind MySQL, SQLite or mongoDB.</description> <repositories>
<url>https://github.com/kangaroo-and-rabbit/archidata</url> <repository>
<licenses> <id>gitea</id>
<license> <url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
<name>Mozilla Public License 2.0</name> </repository>
<url>https://opensource.org/licenses/MPL-2.0</url> </repositories>
<distribution>repo</distribution> <distributionManagement>
</license> <repository>
</licenses> <id>gitea</id>
<developers> <url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
<developer> </repository>
<id>dev1</id> <snapshotRepository>
<name>Edouard DUPIN</name> <id>gitea</id>
<email>edouard.dupin@proton.me</email> <url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
<roles> </snapshotRepository>
<role>Lead Developer</role> </distributionManagement>
</roles>
</developer>
</developers>
<scm>
<url>https://github.com/kangaroo-and-rabbit/archidata</url>
<connection>scm:git:git://github.com/kangaroo-and-rabbit/archidata.git</connection>
<developerConnection>scm:git:ssh:github.com/kangaroo-and-rabbit/archidata.git</developerConnection>
</scm>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
@ -97,6 +89,16 @@
<groupId>org.glassfish.jersey.ext</groupId> <groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId> <artifactId>jersey-bean-validation</artifactId>
</dependency> </dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.4.0-b180830.0359</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.5</version>
</dependency>
<dependency> <dependency>
<groupId>org.glassfish.jaxb</groupId> <groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId> <artifactId>jaxb-runtime</artifactId>
@ -107,6 +109,17 @@
<artifactId>jakarta.ws.rs-api</artifactId> <artifactId>jakarta.ws.rs-api</artifactId>
<version>4.0.0</version> <version>4.0.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.sun.istack</groupId>
<artifactId>istack-commons-runtime</artifactId>
<version>4.2.0</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--> <!-- Serialize and un-serialize request in JSON-->
<dependency> <dependency>
<groupId>org.glassfish.jersey.media</groupId> <groupId>org.glassfish.jersey.media</groupId>
@ -149,7 +162,7 @@
<dependency> <dependency>
<groupId>com.nimbusds</groupId> <groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId> <artifactId>nimbus-jose-jwt</artifactId>
<version>10.2</version> <version>10.0.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.persistence</groupId> <groupId>jakarta.persistence</groupId>
@ -173,7 +186,7 @@
<dependency> <dependency>
<groupId>dev.morphia.morphia</groupId> <groupId>dev.morphia.morphia</groupId>
<artifactId>morphia-core</artifactId> <artifactId>morphia-core</artifactId>
<version>2.4.16</version> <version>2.4.15</version>
</dependency> </dependency>
<!-- MongoDB Java Driver --> <!-- MongoDB Java Driver -->
<dependency> <dependency>
@ -189,6 +202,11 @@
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
<version>9.0.0.CR1</version> <version>9.0.0.CR1</version>
</dependency> </dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- <!--
************************************************************ ************************************************************
** TEST dependency ** ** TEST dependency **
@ -209,7 +227,7 @@
<dependency> <dependency>
<groupId>net.revelc.code.formatter</groupId> <groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId> <artifactId>formatter-maven-plugin</artifactId>
<version>2.26.0</version> <version>2.25.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -218,16 +236,16 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>src/main</sourceDirectory> <sourceDirectory>src</sourceDirectory>
<resources> <resources>
<resource> <resource>
<directory>${basedir}/src/resources</directory> <directory>${basedir}/src/resources</directory>
</resource> </resource>
</resources> </resources>
<testSourceDirectory>src/test</testSourceDirectory> <testSourceDirectory>test/src</testSourceDirectory>
<testResources> <testResources>
<testResource> <testResource>
<directory>${basedir}/src/testResources</directory> <directory>${basedir}/test/resources</directory>
</testResource> </testResource>
</testResources> </testResources>
<plugins> <plugins>
@ -249,7 +267,7 @@
<execution> <execution>
<id>attach-sources</id> <id>attach-sources</id>
<goals> <goals>
<goal>jar-no-fork</goal> <goal>jar</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
@ -272,7 +290,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version> <version>3.5.2</version>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
@ -292,14 +310,10 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version> <version>3.3.0</version>
<executions> <configuration>
<execution> <show>private</show>
<id>attach-javadocs</id> <nohelp>true</nohelp>
<goals> </configuration>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin> </plugin>
<!-- Check the style of the code --> <!-- Check the style of the code -->
<plugin> <plugin>
@ -317,7 +331,7 @@
<plugin> <plugin>
<groupId>net.revelc.code.formatter</groupId> <groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId> <artifactId>formatter-maven-plugin</artifactId>
<version>2.26.0</version> <version>2.24.1</version>
<configuration> <configuration>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding> <lineEnding>LF</lineEnding>
@ -358,29 +372,19 @@
--> -->
</configuration> </configuration>
</plugin> </plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
<reporting>
<plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.7</version> <version>3.3.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.7.0</version>
<extensions>true</extensions>
<configuration> <configuration>
<publishingServerId>central</publishingServerId> <show>public</show>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </reporting>
</project> </project>

View File

@ -1,311 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.6.1</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
<jersey.version>3.1.5</jersey.version>
<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>
<distributionManagement>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
<snapshotRepository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</snapshotRepository>
</distributionManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.istack</groupId>
<artifactId>istack-commons-runtime</artifactId>
<version>${istack.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0-M1</version>
<scope>provided</scope>
</dependency>
<!-- Interface for My-sql & sqlite DB -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.40.0.0</version>
</dependency>
<!-- Interface for JWT token -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.37.1</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0-M1</version>
</dependency>
<!-- Swagger dependencies -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.1.10</version>
</dependency>
<!--
************************************************************
** TEST dependency **
************************************************************
-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.23.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test/src</testSourceDirectory>
<testResources>
<testResource>
<directory>${basedir}/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<!--<encoding>${project.build.sourceEncoding}</encoding>-->
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- For dependabot plugin -->
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<id>generate-depends-file</id>
<goals>
<goal>generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- junit results -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
<!-- Check the style of the code -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<configLocation>CheckStyle.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failOnViolation>true</failOnViolation>
<failsOnError>true</failsOnError>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
</plugin>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.23.0</version>
<configuration>
<encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding>
<configFile>Formatter.xml</configFile>
<directories>
<directory>src/</directory>
<directory>test/src</directory>
</directories>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -7,18 +7,18 @@ import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature; import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
import org.atriasoft.archidata.GlobalConfiguration; import org.kar.archidata.GlobalConfiguration;
import org.atriasoft.archidata.UpdateJwtPublicKey; import org.kar.archidata.UpdateJwtPublicKey;
import org.atriasoft.archidata.api.DataResource; import org.kar.archidata.api.DataResource;
import org.atriasoft.archidata.catcher.ExceptionCatcher; import org.kar.archidata.catcher.ExceptionCatcher;
import org.atriasoft.archidata.catcher.FailExceptionCatcher; import org.kar.archidata.catcher.FailExceptionCatcher;
import org.atriasoft.archidata.catcher.InputExceptionCatcher; import org.kar.archidata.catcher.InputExceptionCatcher;
import org.atriasoft.archidata.catcher.SystemExceptionCatcher; import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.atriasoft.archidata.db.DBConfig; import org.kar.archidata.db.DBConfig;
import org.atriasoft.archidata.filter.CORSFilter; import org.kar.archidata.filter.CORSFilter;
import org.atriasoft.archidata.filter.OptionFilter; import org.kar.archidata.filter.OptionFilter;
import org.atriasoft.archidata.migration.MigrationEngine; import org.kar.archidata.migration.MigrationEngine;
import org.atriasoft.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import sample.archidata.basic.api.Front; import sample.archidata.basic.api.Front;
import sample.archidata.basic.api.HealthCheck; import sample.archidata.basic.api.HealthCheck;
import sample.archidata.basic.api.MediaResource; import sample.archidata.basic.api.MediaResource;

View File

@ -3,9 +3,9 @@ package sample.archidata.basic;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.api.DataResource; import org.kar.archidata.api.DataResource;
import org.atriasoft.archidata.dataAccess.DataFactoryTsApi; import org.kar.archidata.dataAccess.DataFactoryTsApi;
import org.atriasoft.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -8,15 +8,15 @@ import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.atriasoft.archidata.annotation.AsyncType; import org.kar.archidata.annotation.AsyncType;
import org.atriasoft.archidata.annotation.TypeScriptProgress; import org.kar.archidata.annotation.TypeScriptProgress;
import org.atriasoft.archidata.api.DataResource; import org.kar.archidata.api.DataResource;
import org.atriasoft.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOn.AddOnDataJson; import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.atriasoft.archidata.exception.FailException; import org.kar.archidata.exception.FailException;
import org.atriasoft.archidata.exception.InputException; import org.kar.archidata.exception.InputException;
import org.atriasoft.archidata.model.Data; import org.kar.archidata.model.Data;
import org.atriasoft.archidata.tools.DataTools; import org.kar.archidata.tools.DataTools;
import sample.archidata.basic.model.MyModel; import sample.archidata.basic.model.MyModel;
import sample.archidata.basic.model.Season; import sample.archidata.basic.model.Season;
import sample.archidata.basic.model.Series; import sample.archidata.basic.model.Series;

View File

@ -2,7 +2,7 @@ package sample.archidata.basic.migration;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.migration.MigrationSqlStep; import org.kar.archidata.migration.MigrationSqlStep;
import sample.archidata.basic.model.MyModel; import sample.archidata.basic.model.MyModel;
public class Initialization extends MigrationSqlStep { public class Initialization extends MigrationSqlStep {

View File

@ -3,9 +3,9 @@ package sample.archidata.basic.model;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.DataJson; import org.kar.archidata.annotation.DataJson;
import org.atriasoft.archidata.model.Data; import org.kar.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete; import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -1,27 +0,0 @@
package org.atriasoft.archidata.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* In NoSql entity the relation is stored in the 2 part of the entity,
* then it is needed to define the field that store the relation data value in the remote elements.
*/
@Retention(RUNTIME)
@Target({ FIELD, METHOD })
public @interface ManyToManyLocal {
/**
* The entity class that is the target of the
* association.
*/
Class<?> targetEntity();
/**
* The field that owns the revert value. empty if the relationship is unidirectional.
*/
String remoteField() default "";
}

View File

@ -1,45 +0,0 @@
package org.atriasoft.archidata.annotation.apiGenerator;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to explicitly define the nullability of a parameter in an API.
*
* This annotation allows marking a parameter as required (non-null) or optional (nullable),
* overriding any other nullability considerations. It is useful in API generation frameworks
* to ensure precise validation and documentation of method parameters.
*
* <p>Usage:
* - Target: This annotation can be applied to field.
* - Retention: The annotation is retained at runtime, allowing it to be
* processed by frameworks or libraries that handle code generation logic.
*
* <p>Behavior:
* - When applied to a parameter, it explicitly marks it as optional or required in the API.
* This annotation overrides all other considerations regarding nullability.
*
* <p>Example:
* <pre>{@code
* public class User {
* @ReadOnlyField
* @ApiNotNull
* public String username;
* public String email;
* }
* }</pre>
*
* In this example, the `username` field in the `User` class is explicitly marked as non-null in the generated API.
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiNotNull {
/**
* (Optional) Specifies whether the API element can be null.
* If set to `true`, the element is required (non-null).
* If set to `false`, the element is optional (nullable).
*/
boolean value() default true;
}

View File

@ -1,36 +0,0 @@
package org.atriasoft.archidata.annotation.checker;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CheckForeignKeyValidator implements ConstraintValidator<CheckForeignKey, Object> {
Class<?> target = null;
private final static Logger LOGGER = LoggerFactory.getLogger(CheckForeignKeyValidator.class);
@Override
public void initialize(final CheckForeignKey annotation) {
this.target = annotation.target();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value == null) {
return true;
}
try {
final long count = DataAccess.count(this.target, value);
if (count != 1) {
return false;
}
} catch (final Exception e) {
LOGGER.error("Fail to access to the DB");
context.buildConstraintViolationWithTemplate("fail to access on the DB").addConstraintViolation();
return false;
}
return true;
}
}

View File

@ -1,34 +0,0 @@
package org.atriasoft.archidata.catcher;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import org.glassfish.jersey.server.ParamException.QueryParamException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class QueryParamExceptionCatcher implements ExceptionMapper<QueryParamException> {
private static final Logger LOGGER = LoggerFactory.getLogger(QueryParamExceptionCatcher.class);
@Override
public Response toResponse(final QueryParamException exception) {
LOGGER.trace("Catch IllegalArgumentException: {}", exception.getLocalizedMessage());
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
return Response.status(Response.Status.BAD_REQUEST).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(final QueryParamException exception) {
final List<RestInputError> inputError = new ArrayList<>();
inputError.add(new RestInputError("query", exception.getParameterName(), exception.getCause().getMessage()));
final String errorType = "Error on query input='" + exception.getParameterName() + "'";
return new RestErrorResponse(Response.Status.BAD_REQUEST, Instant.now().toString(), errorType,
"Input parsing fail", inputError);
}
}

View File

@ -1,53 +0,0 @@
package org.atriasoft.archidata.converter.Jakarta;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Date;
import org.atriasoft.archidata.tools.DateTools;
import jakarta.annotation.Priority;
import jakarta.ws.rs.ext.ParamConverter;
import jakarta.ws.rs.ext.ParamConverterProvider;
import jakarta.ws.rs.ext.Provider;
@Provider
@Priority(1)
public class DateParamConverterProvider implements ParamConverterProvider {
@SuppressWarnings("unchecked")
@Override
public <T> ParamConverter<T> getConverter(
final Class<T> rawType,
final Type genericType,
final Annotation[] annotations) {
if (rawType != Date.class) {
return null;
}
return (ParamConverter<T>) new DateParamConverter();
}
public class DateParamConverter implements ParamConverter<Date> {
@Override
public Date fromString(final String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
return DateTools.parseDate(value);
} catch (final IOException e) {
throw new IllegalArgumentException("Invalid date format. Please use ISO8601", e);
}
}
@Override
public String toString(final Date value) {
if (value == null) {
return null;
}
return DateTools.serializeMilliWithUTCTimeZone(value);
}
}
}

View File

@ -1,52 +0,0 @@
package org.atriasoft.archidata.converter.Jakarta;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.time.OffsetDateTime;
import org.atriasoft.archidata.tools.DateTools;
import jakarta.ws.rs.ext.ParamConverter;
import jakarta.ws.rs.ext.ParamConverterProvider;
import jakarta.ws.rs.ext.Provider;
@Provider
public class OffsetDateTimeParamConverterProvider implements ParamConverterProvider {
@SuppressWarnings("unchecked")
@Override
public <T> ParamConverter<T> getConverter(
final Class<T> rawType,
final Type genericType,
final Annotation[] annotations) {
if (rawType != OffsetDateTime.class) {
return null;
}
return (ParamConverter<T>) new OffsetDateTimeParamConverter();
}
public class OffsetDateTimeParamConverter implements ParamConverter<OffsetDateTime> {
@Override
public OffsetDateTime fromString(final String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
return DateTools.parseOffsetDateTime(value);
} catch (final IOException e) {
throw new IllegalArgumentException("Invalid date format. Please use ISO8601", e);
}
}
@Override
public String toString(final OffsetDateTime value) {
if (value == null) {
return null;
}
return DateTools.serializeMilliWithUTCTimeZone(value);
}
};
}

View File

@ -1,19 +0,0 @@
package org.atriasoft.archidata.converter.jackson;
import java.io.IOException;
import java.util.Date;
import org.atriasoft.archidata.tools.DateTools;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class DateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
final String value = p.getText();
final Date ret = DateTools.parseDate(value);
return ret;
}
}

View File

@ -1,18 +0,0 @@
package org.atriasoft.archidata.converter.jackson;
import java.io.IOException;
import java.util.Date;
import org.atriasoft.archidata.tools.DateTools;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class DateSerializer extends JsonSerializer<Date> {
@Override
public void serialize(final Date value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeString(DateTools.serializeMilliWithUTCTimeZone(value));
}
}

View File

@ -1,21 +0,0 @@
package org.atriasoft.archidata.converter.jackson;
import java.time.OffsetDateTime;
import java.util.Date;
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());
module.addSerializer(Date.class, new DateSerializer());
module.addDeserializer(Date.class, new DateDeserializer());
module.addSerializer(OffsetDateTime.class, new OffsetDateTimeSerializer());
module.addDeserializer(OffsetDateTime.class, new OffsetDateTimeDeserializer());
return module;
}
}

View File

@ -1,19 +0,0 @@
package org.atriasoft.archidata.converter.jackson;
import java.io.IOException;
import java.time.OffsetDateTime;
import org.atriasoft.archidata.tools.DateTools;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class OffsetDateTimeDeserializer extends JsonDeserializer<OffsetDateTime> {
@Override
public OffsetDateTime deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
final String value = p.getText();
final OffsetDateTime ret = DateTools.parseOffsetDateTime(value);
return ret;
}
}

View File

@ -1,18 +0,0 @@
package org.atriasoft.archidata.converter.jackson;
import java.io.IOException;
import java.time.OffsetDateTime;
import org.atriasoft.archidata.tools.DateTools;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class OffsetDateTimeSerializer extends JsonSerializer<OffsetDateTime> {
@Override
public void serialize(final OffsetDateTime value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeString(DateTools.serializeMilliWithUTCTimeZone(value));
}
}

View File

@ -1,464 +0,0 @@
package org.atriasoft.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.Collection;
import java.util.List;
import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.annotation.ManyToManyLocal;
import org.atriasoft.archidata.dataAccess.CountInOut;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DBAccessSQL;
import org.atriasoft.archidata.dataAccess.DataFactory;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryInList;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.addOnSQL.model.TableCoversGeneric;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.OptionRenameColumn;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.exception.SystemException;
import org.atriasoft.archidata.tools.ContextGenericTools;
import org.bson.types.ObjectId;
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 AddOnManyToManyLocal implements DataAccessAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToManyLocal.class);
static final String SEPARATOR_LONG = "-";
static final String SEPARATOR_UUID = "_";
@Override
public Class<?> getAnnotationClass() {
return ManyToManyLocal.class;
}
@Override
public boolean isCompatibleField(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 || objectClass == ObjectId.class) {
return true;
}
final ManyToManyLocal decorators = field.getDeclaredAnnotation(ManyToManyLocal.class);
if (decorators == null) {
return false;
}
if (decorators.targetEntity() == objectClass) {
return true;
}
return false;
}
@Override
public void insertData(
final DBAccessSQL ioDb,
final PreparedStatement ps,
final Field field,
final Object rootObject,
final CountInOut iii)
throws SQLException, IllegalArgumentException, IllegalAccessException, 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 isUpdateAsync(final Field field) {
return true;
}
@Override
public void asyncUpdate(
final DBAccessSQL ioDb,
final Object previousData,
final String tableName,
final Object primaryKeyValue,
final Field field,
final Object insertedData,
final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
final Object previousDataValue = field.get(previousData);
Collection<?> previousDataCollection = new ArrayList<>();
if (previousDataValue instanceof final Collection<?> tmpCollection) {
previousDataCollection = tmpCollection;
}
final Object insertedDataValue = insertedData;
Collection<?> insertedDataCollection = new ArrayList<>();
if (insertedDataValue instanceof final Collection<?> tmpCollection) {
insertedDataCollection = tmpCollection;
}
// add new Values
for (final Object value : insertedDataCollection) {
if (previousDataCollection.contains(value)) {
continue;
}
actions.add(() -> {
addLinkRemote(ioDb, field, primaryKeyValue, value);
});
}
// remove old values:
for (final Object value : previousDataCollection) {
if (insertedDataCollection.contains(value)) {
continue;
}
actions.add(() -> {
removeLinkRemote(ioDb, field, primaryKeyValue, value);
});
}
}
/** Some action must be done asynchronously for update or remove element
* @param field
* @return */
@Override
public boolean isInsertAsync(final Field field) throws Exception {
return true;
}
/** 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. */
@Override
public void asyncInsert(
final DBAccessSQL ioDb,
final String tableName,
final Object primaryKeyValue,
final Field field,
final Object data,
final List<LazyGetter> actions,
final QueryOptions options) throws Exception {
final Object insertedData = data;
if (insertedData == null) {
return;
}
if (insertedData instanceof final Collection<?> insertedDataCollection) {
for (final Object value : insertedDataCollection) {
actions.add(() -> {
addLinkRemote(ioDb, field, primaryKeyValue, value);
});
}
}
}
@Override
public boolean isPreviousDataNeeded(final Field field) {
return true;
}
@Override
public boolean canInsert(final Field field) {
return isCompatibleField(field);
}
@Override
public boolean canRetrieve(final Field field) {
return isCompatibleField(field);
}
@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();
}
@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) {
throw new SystemException("@ManyToManyLocal must contain a List");
}
final String jsonData = rs.getString(count.value);
count.inc();
if (rs.wasNull()) {
return;
}
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> objectClass = (Class<?>) listType.getActualTypeArguments()[0];
if (objectClass == Long.class) {
final List<Long> dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});
field.set(data, dataParsed);
return;
}
if (objectClass == String.class) {
final List<String> dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});
field.set(data, dataParsed);
return;
}
if (objectClass == UUID.class)
{
final List<UUID> dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});
field.set(data, dataParsed);
return;
}
if (objectClass == ObjectId.class) {
final List<ObjectId> dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<ObjectId>>() {});
field.set(data, dataParsed);
return;
}
final ManyToManyLocal decorators = field.getDeclaredAnnotation(ManyToManyLocal.class);
if (decorators == null) {
return;
}
if (objectClass == decorators.targetEntity()) {
final Class<?> foreignKeyType = AnnotationTools.getPrimaryKeyField(objectClass).getType();
if (foreignKeyType == Long.class) {
final List<Long> idList = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});
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 = () -> {
// TODO: update to have get with abstract types ....
final Object foreignData = ioDb.getsWhere(decorators.targetEntity(),
new Condition(new QueryInList<>(idField.inTable(), idList)));
if (foreignData == null) {
return;
}
field.set(data, foreignData);
};
lazyCall.add(lambda);
}
} else if (foreignKeyType == UUID.class) {
final List<UUID> idList = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});
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 ....
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 == ObjectId.class) {
final List<ObjectId> idList = objectMapper.readValue(jsonData, new TypeReference<List<ObjectId>>() {});
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<ObjectId> childs = new ArrayList<>(idList);
// TODO: update to have get with abstract types ....
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 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 {
// store data as json to response like a no-sql
DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class, options);
}
private static void addLinkLocal(
final DBAccess ioDb,
final Class<?> clazz,
final String clazzPrimaryKeyName,
final Object clazzPrimaryKeyValue,
final String fieldNameToUpdate,
final Object valueToAdd) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("idOfTheObject", clazzPrimaryKeyValue.getClass()),
new OptionSpecifyType("filedNameOfTheObject", valueToAdd.getClass(), true));
options.add(new OptionRenameColumn("idOfTheObject", clazzPrimaryKeyName));
options.add(new OptionRenameColumn("filedNameOfTheObject", fieldNameToUpdate));
final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray());
if (data.filedNameOfTheObject == null) {
data.filedNameOfTheObject = new ArrayList<>();
}
for (final Object elem : data.filedNameOfTheObject) {
if (elem.equals(valueToAdd)) {
return;
}
}
data.filedNameOfTheObject.add(valueToAdd);
ioDb.update(data, data.idOfTheObject, List.of("filedNameOfTheObject"), options.getAllArray());
}
public static void addLink(
final DBAccess ioDb,
final Class<?> clazz,
final Object clazzPrimaryKeyValue,
final String fieldNameToUpdate,
final Object valueToAdd) throws Exception {
final Field localField = AnnotationTools.getFieldNamed(clazz, fieldNameToUpdate);
{
//get local field to find the remote field name:
final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(clazz);
final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null);
final FieldName localFieldName = AnnotationTools.getFieldName(localField, null);
addLinkLocal(ioDb, clazz, primaryKeyColomnName.inTable(), clazzPrimaryKeyValue, localFieldName.inTable(),
valueToAdd);
}
addLinkRemote(ioDb, localField, clazzPrimaryKeyValue, valueToAdd);
}
private static void addLinkRemote(
final DBAccess ioDb,
final Field localField,
final Object localPrimaryKeyValue,
final Object remotePrimaryKeyValue) throws Exception {
final ManyToManyLocal manyLocal = AnnotationTools.get(localField, ManyToManyLocal.class);
// Update the remote elements:
if (manyLocal == null || manyLocal.targetEntity() == null || manyLocal.remoteField() == null
|| manyLocal.remoteField().isEmpty()) {
return;
}
{
//get local field to find the remote field name:
final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(manyLocal.targetEntity());
final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null);
final Field remoteField = AnnotationTools.getFieldNamed(manyLocal.targetEntity(), manyLocal.remoteField());
final FieldName localFieldName = AnnotationTools.getFieldName(remoteField, null);
addLinkLocal(ioDb, manyLocal.targetEntity(), primaryKeyColomnName.inTable(), remotePrimaryKeyValue,
localFieldName.inTable(), localPrimaryKeyValue);
}
}
private static void removeLinkLocal(
final DBAccess ioDb,
final Class<?> clazz,
final String clazzPrimaryKeyName,
final Object clazzPrimaryKeyValue,
final String fieldNameToUpdate,
final Object valueToRemove) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("idOfTheObject", clazzPrimaryKeyValue.getClass()),
new OptionSpecifyType("filedNameOfTheObject", valueToRemove.getClass(), true));
options.add(new OptionRenameColumn("idOfTheObject", clazzPrimaryKeyName));
options.add(new OptionRenameColumn("filedNameOfTheObject", fieldNameToUpdate));
final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray());
if (data.filedNameOfTheObject == null) {
return;
}
final List<Object> newList = new ArrayList<>();
for (final Object elem : data.filedNameOfTheObject) {
if (elem.equals(valueToRemove)) {
continue;
}
newList.add(elem);
}
data.filedNameOfTheObject = newList;
if (data.filedNameOfTheObject.isEmpty()) {
data.filedNameOfTheObject = null;
}
ioDb.update(data, data.idOfTheObject, List.of("filedNameOfTheObject"), options.getAllArray());
}
public static void removeLink(
final DBAccess ioDb,
final Class<?> clazz,
final Object clazzPrimaryKeyValue,
final String fieldNameToUpdate,
final Object valueToRemove) throws Exception {
final Field localField = AnnotationTools.getFieldNamed(clazz, fieldNameToUpdate);
{
//get local field to find the remote field name:
final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(clazz);
final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null);
final FieldName localFieldName = AnnotationTools.getFieldName(localField, null);
removeLinkLocal(ioDb, clazz, primaryKeyColomnName.inTable(), clazzPrimaryKeyValue, localFieldName.inTable(),
valueToRemove);
}
removeLinkRemote(ioDb, localField, clazzPrimaryKeyValue, valueToRemove);
}
private static void removeLinkRemote(
final DBAccess ioDb,
final Field localField,
final Object localPrimaryKeyValue,
final Object remotePrimaryKeyValue) throws Exception {
final ManyToManyLocal manyLocal = AnnotationTools.get(localField, ManyToManyLocal.class);
// Update the remote elements:
if (manyLocal == null || manyLocal.targetEntity() == null || manyLocal.remoteField() == null
|| manyLocal.remoteField().isEmpty()) {
return;
}
{
//get local field to find the remote field name:
final Field primaryKeyField = AnnotationTools.getPrimaryKeyField(manyLocal.targetEntity());
final FieldName primaryKeyColomnName = AnnotationTools.getFieldName(primaryKeyField, null);
final Field remoteField = AnnotationTools.getFieldNamed(manyLocal.targetEntity(), manyLocal.remoteField());
final FieldName localFieldName = AnnotationTools.getFieldName(remoteField, null);
removeLinkLocal(ioDb, manyLocal.targetEntity(), primaryKeyColomnName.inTable(), remotePrimaryKeyValue,
localFieldName.inTable(), localPrimaryKeyValue);
}
}
}

View File

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

View File

@ -1,3 +0,0 @@
package org.atriasoft.archidata.dataAccess.options;
public class QueryOption {}

View File

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

View File

@ -1,170 +0,0 @@
package org.atriasoft.archidata.tools;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DateTools {
private final static Logger LOGGER = LoggerFactory.getLogger(DateTools.class);
// List of supported parsers for flexible date string parsing.
// Includes patterns with optional parts, slashes, and ISO standard formats.
static final List<DateTimeFormatter> FORMATTERS = Arrays.asList(
DateTimeFormatter.ofPattern("[yyyy[-MM[-dd]]]['T'][' '][HH[:mm[:ss['.'nnnnnnnnn]]]]XXXXX"),
DateTimeFormatter.ofPattern("[yyyy[/MM[/dd]]]['T'][' '][HH[:mm[:ss['.'nnnnnnnnn]]]]XXXXX"),
DateTimeFormatter.ISO_OFFSET_DATE_TIME, // e.g., 2025-04-04T15:30:00+02:00
DateTimeFormatter.ISO_ZONED_DATE_TIME, // e.g., 2025-04-04T15:30:00+02:00[Europe/Paris]
DateTimeFormatter.ISO_INSTANT // e.g., 2025-04-04T13:30:00Z
);
/**
* Attempts to parse a date string into an OffsetDateTime using a flexible list of patterns.
* Supports ISO 8601 formats, optional zone, and fallback to LocalDate or LocalTime if needed.
*
* @param dateString the date string to parse
* @return OffsetDateTime representation of the parsed input
* @throws IOException if no supported format matches the input
*/
public static OffsetDateTime parseOffsetDateTime(final String dateString) throws IOException {
return parseOffsetDateTime(dateString, false);
}
/**
* Attempts to parse a date string into an OffsetDateTime using a flexible list of patterns.
* Supports ISO 8601 formats, optional zone, and fallback to LocalDate or LocalTime if needed.
*
* @param dateString the date string to parse
* @param missingAsUTC Parse date when missing the time zone consider it as a UTC Date-time
* @return OffsetDateTime representation of the parsed input
* @throws IOException if no supported format matches the input
*/
public static OffsetDateTime parseOffsetDateTime(final String dateString, final boolean missingAsUTC)
throws IOException {
if (dateString == null) {
return null;
}
for (final DateTimeFormatter formatter : FORMATTERS) {
try {
return OffsetDateTime.parse(dateString, formatter);
} catch (final DateTimeParseException ex) {
if (missingAsUTC) {
// If the date string is missing a zone, try appending "Z"
try {
if (dateString.endsWith("Z") || dateString.endsWith("z")) {
continue;
}
return OffsetDateTime.parse(dateString + "Z", formatter);
} catch (final DateTimeParseException ex2) {
// Still failed, try next pattern
}
}
}
}
throw new IOException("Unrecognized DATE format: '" + dateString + "' supported format ISO8601");
}
/**
* Parses a flexible date string and returns a java.util.Date,
* using system default time-zone for conversion.
*
* @param dateString the input string to parse
* @return The parsed Date
* @throws IOException if parsing fails.
*/
public static Date parseDate(final String dateString) throws IOException {
final OffsetDateTime dateTime = parseOffsetDateTime(dateString, true);
dateTime.atZoneSameInstant(ZoneId.systemDefault());
return Date.from(dateTime.toInstant());
}
/**
* Formatter for date-time with milliseconds and original timezone offset (e.g., 2025-04-06T15:00:00.123+02:00)
*/
public static final DateTimeFormatter PATTERN_MS_TIME_WITH_ZONE = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss'.'SSSXXX");
/**
* Serializes an OffsetDateTime to a string including milliseconds and the original timezone offset.
* Example output: 2025-04-06T15:00:00.123+02:00
*/
public static String serializeMilliWithOriginalTimeZone(final OffsetDateTime offsetDateTime) {
if (offsetDateTime == null) {
return null;
}
return offsetDateTime.format(PATTERN_MS_TIME_WITH_ZONE);
}
/**
* Converts a java.util.Date to OffsetDateTime using the system's default timezone,
* then serializes it to a string with milliseconds and original timezone offset.
*/
public static String serializeMilliWithOriginalTimeZone(final Date date) {
if (date == null) {
return null;
}
return serializeMilliWithOriginalTimeZone(date.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime());
}
/**
* Formatter for date-time with milliseconds in UTC offset (e.g., 2025-04-06T13:00:00.123Z)
*/
public static final DateTimeFormatter PATTERN_MS_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'.'SSSX");
/**
* Serializes an OffsetDateTime to a string with milliseconds in UTC.
* The offset is explicitly changed to UTC before formatting.
*/
public static String serializeMilliWithUTCTimeZone(final OffsetDateTime offsetDateTime) {
if (offsetDateTime == null) {
return null;
}
return offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC).format(PATTERN_MS_TIME);
}
/**
* Converts a java.util.Date to OffsetDateTime in the system's default timezone,
* then serializes it with milliseconds in UTC.
*/
public static String serializeMilliWithUTCTimeZone(final Date date) {
if (date == null) {
return null;
}
return serializeMilliWithUTCTimeZone(date.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime());
}
/**
* Formatter for date-time with nanoseconds in UTC offset (e.g., 2025-04-06T13:00:00.123456789Z)
*/
public static final DateTimeFormatter PATTERN_NS_TIME = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss'.'nnnnnnnnnX");
/**
* Serializes an OffsetDateTime to a string with nanosecond precision in UTC.
*/
public static String serializeNanoWithUTCTimeZone(final OffsetDateTime offsetDateTime) {
if (offsetDateTime == null) {
return null;
}
return offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC).format(PATTERN_NS_TIME);
}
/**
* Converts a java.util.Date to OffsetDateTime in the system's default timezone,
* then serializes it with nanoseconds in UTC.
*/
public static String serializeNanoWithUTCTimeZone(final Date date) {
if (date == null) {
return null;
}
return serializeNanoWithUTCTimeZone(date.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime());
}
}

View File

@ -1,490 +0,0 @@
package org.atriasoft.archidata.tools;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpRequest.Builder;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.atriasoft.archidata.exception.RESTErrorResponseException;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import jakarta.ws.rs.core.HttpHeaders;
public class RESTApiRequest {
final static Logger LOGGER = LoggerFactory.getLogger(RESTApiRequest.class);
private final String url;
private final String token;
private final ObjectMapper mapper;
private String serializedBodyString = null;
private byte[] serializedBodyByte = null;
private String contentType = null;
private final Map<String, String> headers = new HashMap<>();
private final Map<String, String> queryParam = new HashMap<>();
private String verb = "GET";
/**
* Constructor to initialize the RESTApiRequest with base URL and authorization token.
*
* @param url The base URL of the API.
* @param token The Bearer token for authentication.
*/
public RESTApiRequest(final String url, final String token) {
this.url = url;
this.token = token;
this.mapper = ContextGenericTools.createObjectMapper();
}
/**
* Sets the HTTP method (GET, POST, etc.).
*
* @param verb The HTTP verb to use.
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest verb(final String verb) {
this.verb = verb;
return this;
}
/**
* Sets the request body as a raw String.
*
* @param body The raw string body.
* @param contentType The content type of the request body.
* @return The updated RESTApiRequest instance.
*/
public <TYPE_BODY> RESTApiRequest bodyString(final String body, final String contentType) {
this.serializedBodyByte = null;
this.serializedBodyString = body;
this.contentType = contentType;
return this;
}
/**
* Sets the request body as a raw String.
*
* @param body The raw string body (consider as "text/plain").
* @return The updated RESTApiRequest instance.
*/
public <TYPE_BODY> RESTApiRequest bodyString(final String body) {
this.serializedBodyByte = null;
this.serializedBodyString = body;
this.contentType = "text/plain";
return this;
}
/**
* Serializes a Map to a JSON string and sets it as the body.
*
* @param data A map representing the body content.
* @return The updated RESTApiRequest instance.
* @throws JsonProcessingException If the map fails to serialize.
*/
public <TYPE_BODY> RESTApiRequest bodyMap(final Map<String, Object> data) throws JsonProcessingException {
this.serializedBodyByte = null;
this.serializedBodyString = this.mapper.writeValueAsString(data);
this.contentType = "application/json";
return this;
}
/**
* Sets the request body as a byte array.
*
* @param body The byte array representing the body.
* @param contentType The content type of the body.
* @return The updated RESTApiRequest instance.
*/
public <TYPE_BODY> RESTApiRequest bodyByte(final byte[] body, final String contentType) {
this.serializedBodyByte = body;
this.serializedBodyString = null;
this.contentType = contentType;
return this;
}
/**
* Serializes a POJO into JSON and sets it as the body.
*
* @param body A Java object to serialize.
* @return The updated RESTApiRequest instance.
* @throws JsonProcessingException If serialization fails.
*/
public <TYPE_BODY> RESTApiRequest bodyJson(final TYPE_BODY body) throws JsonProcessingException {
this.serializedBodyString = this.mapper.writeValueAsString(body);
this.contentType = "application/json";
return this;
}
/**
* Set data as a json body.
*
* @param body a serialized Json object.
* @return The updated RESTApiRequest instance.
*/
public <TYPE_BODY> RESTApiRequest bodyAsJson(final String body) {
this.serializedBodyString = body;
this.contentType = "application/json";
return this;
}
/**
* Builds a multipart/form-data request body from a map of fields.
* Handles both File and standard form fields.
*
* @param body A map of key-values where values can be File or String.
* @return The updated RESTApiRequest instance.
* @throws IOException If reading files fails.
*/
public <TYPE_BODY> RESTApiRequest bodyMultipart(final Map<String, Object> body) throws IOException {
this.serializedBodyString = null;
LOGGER.trace("body (MULTIPART)");
// Create multipart key element
final String boundary = (new ObjectId()).toString();
this.contentType = "multipart/form-data; boundary=" + boundary;
// create the body;
final List<byte[]> bodyParts = new ArrayList<>();
for (final Map.Entry<String, Object> entry : body.entrySet()) {
final StringBuilder partHeader = new StringBuilder();
partHeader.append("--").append(boundary).append("\r\n");
if (entry.getValue() instanceof File) {
final File file = (File) entry.getValue();
partHeader.append("Content-Disposition: form-data; name=\"").append(entry.getKey())
.append("\"; filename=\"").append(file.getName()).append("\"\r\n");
partHeader.append("Content-Type: application/octet-stream\r\n\r\n");
bodyParts.add(partHeader.toString().getBytes());
bodyParts.add(Files.readAllBytes(file.toPath()));
bodyParts.add("\r\n".getBytes());
} else {
partHeader.append("Content-Disposition: form-data; name=\"").append(entry.getKey())
.append("\"\r\n\r\n");
if (entry.getValue() == null) {
partHeader.append("null\r\n");
} else {
partHeader.append(entry.getValue().toString()).append("\r\n");
}
bodyParts.add(partHeader.toString().getBytes());
}
}
bodyParts.add(("--" + boundary + "--\r\n").getBytes());
final int totalSize = bodyParts.stream().mapToInt(b -> b.length).sum();
this.serializedBodyByte = new byte[totalSize];
int position = 0;
for (final byte[] part : bodyParts) {
System.arraycopy(part, 0, this.serializedBodyByte, position, part.length);
position += part.length;
}
return this;
}
/**
* Adds a query parameter to the request URL.
*
* @param paramKey The parameter name.
* @param body The parameter value.
* @return The updated RESTApiRequest instance.
*/
public <TYPE_PARAM> RESTApiRequest queryParam(final String paramKey, final TYPE_PARAM body) {
this.queryParam.put(paramKey, body.toString());
return this;
}
/**
* Sets the HTTP verb to GET.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest get() {
verb("GET");
return this;
}
/**
* Sets the HTTP verb to PUT.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest put() {
verb("PUT");
return this;
}
/**
* Sets the HTTP verb to POST.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest post() {
verb("POST");
return this;
}
/**
* Sets the HTTP verb to PATCH.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest patch() {
verb("PATCH");
return this;
}
/**
* Sets the HTTP verb to DELETE.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest delete() {
verb("DELETE");
return this;
}
/**
* Sets the HTTP verb to ARCHIVE.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest archive() {
verb("ARCHIVE");
return this;
}
/**
* Sets the HTTP verb to RESTORE.
*
* @return The updated RESTApiRequest instance.
*/
public RESTApiRequest restore() {
verb("RESTORE");
return this;
}
/**
* Sends the request and parses the response into a List of objects.
*
* @param clazz The class of each element in the expected response.
* @return List of parsed response objects.
* @throws RESTErrorResponseException If an error response is received.
* @throws IOException If the request fails.
* @throws InterruptedException If the request is interrupted.
*/
public <TYPE_RESPONSE> List<TYPE_RESPONSE> fetchList(final Class<TYPE_RESPONSE> clazz)
throws RESTErrorResponseException, IOException, InterruptedException {
final HttpRequest request = fetch();
return callAndParseRequestList(clazz, request);
}
/**
* Sends the request and parses the response into a single object.
*
* @param clazz The class of the expected response.
* @return Parsed response object.
* @throws RESTErrorResponseException If an error response is received.
* @throws IOException If the request fails.
* @throws InterruptedException If the request is interrupted.
*/
public <TYPE_RESPONSE> TYPE_RESPONSE fetch(final Class<TYPE_RESPONSE> clazz)
throws RESTErrorResponseException, IOException, InterruptedException {
final HttpRequest request = fetch();
return callAndParseRequest(clazz, request);
}
/**
* Builds a query parameter string from a map of key-value pairs.
*
* <p>This method encodes each key and value using UTF-8 encoding to ensure that
* the resulting query string is safe for use in a URL. The encoded key-value pairs
* are then joined together with `&amp;` separators.</p>
*
* @param params A map containing query parameter names and their corresponding values.
* Both keys and values will be URL-encoded.
* @return A URL-encoded query string.
*/
public static String buildQueryParams(final Map<String, String> params) {
return params.entrySet().stream().map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "="
+ URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)).collect(Collectors.joining("&"));
}
/**
* Builds the final HttpRequest based on method, headers, and body.
*
* @return A built HttpRequest instance.
* @throws RESTErrorResponseException If error happens during body serialization.
* @throws IOException If body serialization fails.
* @throws InterruptedException If the request is interrupted.
*/
public HttpRequest fetch() throws RESTErrorResponseException, IOException, InterruptedException {
Builder requestBuilding = null;
final String queryParams = buildQueryParams(this.queryParam);
if (queryParams == null || queryParams.isEmpty()) {
requestBuilding = createRequestBuilder("");
} else {
requestBuilding = createRequestBuilder("?" + queryParams);
}
if (this.contentType != null) {
requestBuilding.header("Content-Type", this.contentType);
}
for (final Map.Entry<String, String> entry : this.headers.entrySet()) {
requestBuilding.header(entry.getKey(), entry.getValue());
}
if (this.serializedBodyString != null) {
LOGGER.trace("publish body: {}", this.serializedBodyString);
return requestBuilding.method(this.verb, BodyPublishers.ofString(this.serializedBodyString)).build();
}
if (this.serializedBodyByte != null) {
LOGGER.trace("publish body: {}", this.serializedBodyString);
return requestBuilding.method(this.verb, BodyPublishers.ofByteArray(this.serializedBodyByte)).build();
}
return requestBuilding.method(this.verb, BodyPublishers.ofString("")).build();
}
/**
* Performs a raw GET request and returns the raw HttpResponse as bytes.
*
* @param urlOffset The URL path relative to the base URL.
* @return Raw HTTP response in byte array.
* @throws IOException If the request fails.
* @throws InterruptedException If the request is interrupted.
*/
protected HttpResponse<byte[]> getRaw(final String urlOffset) throws IOException, InterruptedException {
final Builder requestBuilding = createRequestBuilder(urlOffset);
final HttpRequest request = requestBuilding.method("GET", BodyPublishers.ofString("")).build();
final HttpClient client = HttpClient.newHttpClient();
// client.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
return client.send(request, HttpResponse.BodyHandlers.ofByteArray());
}
/**
* Creates and initializes a HttpRequest.Builder with authorization and URL.
*
* @param urlOffset The URL path relative to the base URL.
* @return Initialized HttpRequest.Builder.
*/
private Builder createRequestBuilder(final String urlOffset) {
Builder requestBuilding = HttpRequest.newBuilder().version(Version.HTTP_1_1)
.uri(URI.create(this.url + urlOffset));
if (this.token != null) {
requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token);
}
return requestBuilding;
}
/**
* Sends the request and parses the response as a single object.
*
* @param clazzReturn The expected class of the response.
* @param request The built HttpRequest to send.
* @return Parsed object of the response.
* @throws RESTErrorResponseException If an error response is received.
* @throws IOException If the response cannot be parsed or network fails.
* @throws InterruptedException If the request is interrupted.
*/
@SuppressWarnings("unchecked")
private <TYPE_RESPONSE> TYPE_RESPONSE callAndParseRequest(
final Class<TYPE_RESPONSE> clazzReturn,
final HttpRequest request) throws RESTErrorResponseException, IOException, InterruptedException {
final HttpClient client = HttpClient.newHttpClient();
// client.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
if (clazzReturn == HttpResponse.class) {
return (TYPE_RESPONSE) httpResponse;
}
if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) {
LOGGER.trace("Receive Error: {}", httpResponse.body());
try {
final RESTErrorResponseException out = this.mapper.readValue(httpResponse.body(),
RESTErrorResponseException.class);
throw out;
} catch (final InvalidDefinitionException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
} catch (final MismatchedInputException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
} catch (final JsonParseException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
}
}
if (clazzReturn == Void.class || clazzReturn == void.class) {
return null;
}
if (clazzReturn.equals(String.class)) {
return (TYPE_RESPONSE) httpResponse.body();
}
LOGGER.trace("Receive model: {} with data: '{}'", clazzReturn.getCanonicalName(), httpResponse.body());
return this.mapper.readValue(httpResponse.body(), clazzReturn);
}
/**
* Sends the request and parses the response as a list of objects.
*
* @param clazzReturn The class of the expected response elements.
* @param request The HttpRequest to send.
* @return List of parsed response objects.
* @throws RESTErrorResponseException If an error response is received.
* @throws IOException If the response cannot be parsed or network fails.
* @throws InterruptedException If the request is interrupted.
*/
@SuppressWarnings("unchecked")
private <TYPE_RESPONSE> List<TYPE_RESPONSE> callAndParseRequestList(
final Class<TYPE_RESPONSE> clazzReturn,
final HttpRequest request) throws IOException, InterruptedException, RESTErrorResponseException {
final HttpClient client = HttpClient.newHttpClient();
// client.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) {
LOGGER.trace("Receive Error: {}", httpResponse.body());
try {
final RESTErrorResponseException out = this.mapper.readValue(httpResponse.body(),
RESTErrorResponseException.class);
throw out;
} catch (final InvalidDefinitionException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
} catch (final MismatchedInputException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
} catch (final JsonParseException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
}
}
LOGGER.trace("Receive model: List<{}> with data: '{}'", clazzReturn.getCanonicalName(), httpResponse.body());
return this.mapper.readValue(httpResponse.body(),
this.mapper.getTypeFactory().constructCollectionType(List.class, clazzReturn));
}
}

View File

@ -1,7 +1,7 @@
package org.atriasoft.archidata; package org.kar.archidata;
import org.atriasoft.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.JWTWrapper; import org.kar.archidata.tools.JWTWrapper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -6,14 +6,14 @@ import java.lang.reflect.Parameter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.checker.Checker; import org.kar.archidata.annotation.checker.Checker;
import org.atriasoft.archidata.annotation.checker.CollectionItemNotNull; import org.kar.archidata.annotation.checker.CollectionItemNotNull;
import org.atriasoft.archidata.annotation.checker.CollectionItemUnique; import org.kar.archidata.annotation.checker.CollectionItemUnique;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.kar.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.options.OptionRenameColumn; import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName; import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -20,7 +20,7 @@ import java.lang.annotation.Target;
* - When a field is annotated with @DataNotRead, it will not be included in the * - When a field is annotated with @DataNotRead, it will not be included in the
* default data retrieval process from the database. * default data retrieval process from the database.
* - To override this behavior and read all columns, including those marked with * - To override this behavior and read all columns, including those marked with
* `@DataNotRead`, the query must include the option ReadAllColumn. * @DataNotRead, the query must include the option ReadAllColumn.
* *
* <p>Example: * <p>Example:
* <pre>{@code * <pre>{@code

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation; package org.kar.archidata.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.addOn; package org.kar.archidata.annotation.addOn;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.apiGenerator; package org.kar.archidata.annotation.apiGenerator;
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -9,11 +9,6 @@ import java.lang.annotation.Target;
@Retention(RUNTIME) @Retention(RUNTIME)
@Target(FIELD) @Target(FIELD)
public @interface ApiAccessLimitation { public @interface ApiAccessLimitation {
/**
* (Optional) The field is accessible in read (GET)
*/
boolean readable() default true;
/** /**
* (Optional) The field is accessible in creation (POST) * (Optional) The field is accessible in creation (POST)
*/ */

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.apiGenerator; package org.kar.archidata.annotation.apiGenerator;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.apiGenerator; package org.kar.archidata.annotation.apiGenerator;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.apiGenerator; package org.kar.archidata.annotation.apiGenerator;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -22,8 +22,7 @@ import java.lang.annotation.Target;
* more flexible API designs where certain inputs can be omitted. * more flexible API designs where certain inputs can be omitted.
* *
* <p>Example: * <p>Example:
* * <pre>{@code
* {@code
* public class AlbumService { * public class AlbumService {
* *
* @POST * @POST
@ -40,8 +39,7 @@ import java.lang.annotation.Target;
* // some code * // some code
* } * }
* } * }
* } * }</pre>
*
* *
* Note: @FormDataParam must be allway at the last position. * Note: @FormDataParam must be allway at the last position.
* *
@ -49,8 +47,7 @@ import java.lang.annotation.Target;
* marked as optional, allowing the client to omit them when calling the API. * marked as optional, allowing the client to omit them when calling the API.
* *
* <p>Generated TypeScript code example: * <p>Generated TypeScript code example:
* * <pre>{@code
* {@code
* //Add a cover on a specific album * //Add a cover on a specific album
* export function uploadCover({ * export function uploadCover({
* restConfig, * restConfig,
@ -67,11 +64,10 @@ import java.lang.annotation.Target;
* uri?: string, // element is optional * uri?: string, // element is optional
* }, * },
* callbacks?: RESTCallbacks, * callbacks?: RESTCallbacks,
* }): Promise<Album> { ... } * }): Promise<Album> { ...
* } * }</pre>
* *
* * The generated TypeScript function reflects the optional nature of the form data parameters.
* The generated TypeScript function reflects the optional nature of the form data parameters
*/ */
@Target({ ElementType.PARAMETER }) @Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.apiGenerator; package org.kar.archidata.annotation.apiGenerator;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -25,7 +25,7 @@ import java.lang.annotation.Target;
* the older XMLHttpRequest interface is utilized. * the older XMLHttpRequest interface is utilized.
* *
* <p>Example: * <p>Example:
* {@code * <pre>{@code
* public class SeasonService { * public class SeasonService {
* *
* @POST * @POST
@ -41,13 +41,13 @@ import java.lang.annotation.Target;
* // Upload logic * // Upload logic
* } * }
* } * }
* } * }</pre>
* *
* In this example, the uploadCover method will generate a client-side API * In this example, the uploadCover method will generate a client-side API
* with progress tracking capabilities using XMLHttpRequest. * with progress tracking capabilities using XMLHttpRequest.
* *
* <p>Generated TypeScript code example: * <p>Generated TypeScript code example:
* {@code * <pre>{@code
* export function uploadCover({ * export function uploadCover({
* restConfig, * restConfig,
* params, * params,
@ -62,9 +62,8 @@ import java.lang.annotation.Target;
* file: File, * file: File,
* }, * },
* callbacks?: RESTCallbacks, * callbacks?: RESTCallbacks,
* }): Promise<Season> {...} * }): Promise<Season> {...
* } * }</pre>
*
* *
*/ */
@Target({ ElementType.PARAMETER, ElementType.METHOD }) @Target({ ElementType.PARAMETER, ElementType.METHOD })

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -9,15 +9,7 @@ import jakarta.validation.Constraint;
import jakarta.validation.Payload; import jakarta.validation.Payload;
@Constraint(validatedBy = CheckForeignKeyValidator.class) @Constraint(validatedBy = CheckForeignKeyValidator.class)
@Target({ ElementType.TYPE, // @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
ElementType.METHOD, //
ElementType.FIELD, //
ElementType.ANNOTATION_TYPE, //
ElementType.CONSTRUCTOR, //
ElementType.PARAMETER, //
ElementType.TYPE_USE, //
})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface CheckForeignKey { public @interface CheckForeignKey {
Class<?> target(); Class<?> target();

View File

@ -0,0 +1,43 @@
package org.kar.archidata.annotation.checker;
import java.util.Collection;
import org.kar.archidata.dataAccess.DataAccess;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CheckForeignKeyValidator implements ConstraintValidator<CheckForeignKey, Object> {
Class<?> target = null;
@Override
public void initialize(final CheckForeignKey annotation) {
this.target = annotation.target();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value != null) {
return true;
}
if (value instanceof final Collection<?> tmpCollection) {
final Object[] elements = tmpCollection.toArray();
for (final Object element : elements) {
if (element == null) {
continue;
}
try {
final long count = DataAccess.count(this.target, element);
if (count != 1) {
return false;
}
} catch (final Exception e) {
// TODO ...
return false;
}
}
}
return true;
}
}

View File

@ -1,11 +1,11 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.atriasoft.archidata.dataAccess.options.CheckFunctionInterface; import org.kar.archidata.dataAccess.options.CheckFunctionInterface;
/** /**
* The Checker annotation is used to specify a checker class that automatically * The Checker annotation is used to specify a checker class that automatically

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.util.Collection; import java.util.Collection;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.util.Collection; import java.util.Collection;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.checker; package org.kar.archidata.annotation.checker;
import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext; import jakarta.validation.ConstraintValidatorContext;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.method; package org.kar.archidata.annotation.method;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.method; package org.kar.archidata.annotation.method;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.annotation.security; package org.kar.archidata.annotation.security;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.api; package org.kar.archidata.api;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -21,18 +21,18 @@ import java.util.UUID;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.security.PermitTokenInURI;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.QueryCondition;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.exception.FailException;
import org.atriasoft.archidata.filter.GenericContext;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.apiGenerator.ApiInputOptional;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -157,8 +157,13 @@ public class DataResource {
return null; return null;
} }
protected String getMimeType(final String extension) throws IOException { public Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
return switch (extension.toLowerCase()) { throws IOException {
// determine mime type:
Data injectedData = new Data();
String mimeType = "";
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
mimeType = switch (extension.toLowerCase()) {
case "jpg", "jpeg" -> "image/jpeg"; case "jpg", "jpeg" -> "image/jpeg";
case "png" -> "image/png"; case "png" -> "image/png";
case "webp" -> "image/webp"; case "webp" -> "image/webp";
@ -167,15 +172,6 @@ public class DataResource {
case "webm" -> "video/webm"; case "webm" -> "video/webm";
default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'"); default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}; };
}
public Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
throws IOException {
// determine mime type:
Data injectedData = new Data();
String mimeType = "";
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
mimeType = getMimeType(extension);
injectedData.mimeType = mimeType; injectedData.mimeType = mimeType;
injectedData.sha512 = sha512; injectedData.sha512 = sha512;
final String tmpPath = getTmpFileInData(tmpUID); final String tmpPath = getTmpFileInData(tmpUID);
@ -373,9 +369,10 @@ public class DataResource {
} }
LOGGER.info("input size image: {}x{} type={}", inputImage.getWidth(), inputImage.getHeight(), LOGGER.info("input size image: {}x{} type={}", inputImage.getWidth(), inputImage.getHeight(),
inputImage.getType()); inputImage.getType());
final int scaledWidth = ConfigBaseVariable.getThumbnailWidth(); final int scaledWidth = 250;
final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth()
* scaledWidth); * scaledWidth);
// creates output image // creates output image
final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType()); final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
@ -384,10 +381,16 @@ public class DataResource {
LOGGER.info("output size image: {}x{}", scaledWidth, scaledHeight); LOGGER.info("output size image: {}x{}", scaledWidth, scaledHeight);
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null); g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose(); g2d.dispose();
for (final String data : ImageIO.getWriterFormatNames()) {
LOGGER.info("availlable format: {}", data);
}
// create the output stream: // create the output stream:
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { try {
ImageIO.write(outputImage, ConfigBaseVariable.getThumbnailFormat(), baos); // 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);
} catch (final IOException e) { } catch (final IOException e) {
e.printStackTrace(); e.printStackTrace();
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain") return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain")
@ -395,20 +398,12 @@ public class DataResource {
} }
final byte[] imageData = baos.toByteArray(); final byte[] imageData = baos.toByteArray();
LOGGER.info("output length {}", imageData.length); LOGGER.info("output length {}", imageData.length);
if (imageData.length == 0) { // Response.ok(new ByteArrayInputStream(imageData)).build();
LOGGER.error("Fail to convert image... Availlable format:");
for (final String data : ImageIO.getWriterFormatNames()) {
LOGGER.error(" - {}", data);
}
}
final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH,
imageData.length); imageData.length);
try { //out.type("image/jpeg");
out.type(getMimeType(ConfigBaseVariable.getThumbnailFormat())); out.type("image/webp");
} catch (final IOException ex) { //out.type("image/png");
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR,
"Fail to convert mime type of " + ConfigBaseVariable.getThumbnailFormat(), ex);
}
// TODO: move this in a decorator !!! // TODO: move this in a decorator !!!
final CacheControl cc = new CacheControl(); final CacheControl cc = new CacheControl();
cc.setMaxAge(3600); cc.setMaxAge(3600);

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.api; package org.kar.archidata.api;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.api; package org.kar.archidata.api;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.api; package org.kar.archidata.api;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.api; package org.kar.archidata.api;
import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource; import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.backup; package org.kar.archidata.backup;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,6 +1,6 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.atriasoft.archidata.exception.FailException; import org.kar.archidata.exception.FailException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
@ -11,16 +11,15 @@ public class GenericCatcher {
public static void addAll(final ResourceConfig rc) { public static void addAll(final ResourceConfig rc) {
// Generic Json parsing error // Generic Json parsing error
rc.register(JacksonExceptionCatcher.class); rc.register(JacksonExceptionCatcher.class);
// Catch jakarta generic errors
rc.register(WebApplicationExceptionCatcher.class);
// Archidata exceptions // Archidata exceptions
rc.register(InputExceptionCatcher.class); rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class); rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class); rc.register(FailExceptionCatcher.class);
// generic Exception catcher // generic Exception catcher
rc.register(ConstraintViolationExceptionCatcher.class);
rc.register(QueryParamExceptionCatcher.class);
rc.register(ExceptionCatcher.class); rc.register(ExceptionCatcher.class);
// Catch jakarta generic errors rc.register(ConstraintViolationExceptionCatcher.class);
rc.register(WebApplicationExceptionCatcher.class);
} }
} }

View File

@ -1,6 +1,6 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.atriasoft.archidata.exception.InputException; import org.kar.archidata.exception.InputException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,10 +1,10 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -27,17 +27,6 @@ public class RestInputError {
public RestInputError() {} public RestInputError() {}
public RestInputError(final String argument, final String path, final String message) {
this.path = argument;
this.path = path;
this.message = message;
}
public RestInputError(final String path, final String message) {
this.path = path;
this.message = message;
}
public RestInputError(final Path path, final String message) { public RestInputError(final Path path, final String message) {
final Matcher matcher = PATTERN.matcher(path.toString()); final Matcher matcher = PATTERN.matcher(path.toString());
if (matcher.find()) { if (matcher.find()) {
@ -50,6 +39,11 @@ public class RestInputError {
this.message = message; this.message = message;
} }
public RestInputError(final String path, final String message) {
this.path = path;
this.message = message;
}
String getFullPath() { String getFullPath() {
if (this.path == null) { if (this.path == null) {
return this.argument; return this.argument;

View File

@ -1,6 +1,6 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.atriasoft.archidata.exception.SystemException; import org.kar.archidata.exception.SystemException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.catcher; package org.kar.archidata.catcher;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.checker; package org.kar.archidata.checker;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.sql.Timestamp; import java.sql.Timestamp;
@ -14,21 +14,21 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.atriasoft.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey; import org.kar.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.Checker; import org.kar.archidata.annotation.checker.Checker;
import org.atriasoft.archidata.annotation.checker.CollectionItemNotNull; import org.kar.archidata.annotation.checker.CollectionItemNotNull;
import org.atriasoft.archidata.annotation.checker.CollectionItemUnique; import org.kar.archidata.annotation.checker.CollectionItemUnique;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.kar.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.dataAccess.DBAccess; import org.kar.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryCondition;
import org.atriasoft.archidata.dataAccess.QueryOptions; import org.kar.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.options.CheckFunctionInterface; import org.kar.archidata.dataAccess.options.CheckFunctionInterface;
import org.atriasoft.archidata.dataAccess.options.CheckFunctionVoid; import org.kar.archidata.dataAccess.options.CheckFunctionVoid;
import org.atriasoft.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.ConditionChecker; import org.kar.archidata.dataAccess.options.ConditionChecker;
import org.atriasoft.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.atriasoft.archidata.exception.InputException; import org.kar.archidata.exception.InputException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

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

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.converter.jackson; package org.kar.archidata.converter.jackson;
import java.io.IOException; import java.io.IOException;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.converter.jackson; package org.kar.archidata.converter.jackson;
import java.io.IOException; import java.io.IOException;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.converter.morphia; package org.kar.archidata.converter.morphia;
import java.sql.Timestamp; import java.sql.Timestamp;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
/** Java does not permit to set return data (eg: integer) in the function parameter. This class permit to update a value as in/out function parameters. */ /** Java does not permit to set return data (eg: integer) in the function parameter. This class permit to update a value as in/out function parameters. */
public class CountInOut { public class CountInOut {

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
@ -6,21 +6,21 @@ import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.AnnotationTools; import org.kar.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName; import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.FilterValue; import org.kar.archidata.dataAccess.options.FilterValue;
import org.atriasoft.archidata.dataAccess.options.Limit; import org.kar.archidata.dataAccess.options.Limit;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType; import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.QueryOption; import org.kar.archidata.dataAccess.options.QueryOption;
import org.atriasoft.archidata.dataAccess.options.TransmitKey; import org.kar.archidata.dataAccess.options.TransmitKey;
import org.atriasoft.archidata.db.DbConfig; import org.kar.archidata.db.DbConfig;
import org.atriasoft.archidata.db.DbIo; import org.kar.archidata.db.DbIo;
import org.atriasoft.archidata.db.DbIoFactory; import org.kar.archidata.db.DbIoFactory;
import org.atriasoft.archidata.db.DbIoMorphia; import org.kar.archidata.db.DbIoMorphia;
import org.atriasoft.archidata.db.DbIoSql; import org.kar.archidata.db.DbIoSql;
import org.atriasoft.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ContextGenericTools; import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -185,8 +185,7 @@ public abstract class DBAccess implements Closeable {
/** @param <T> /** @param <T>
* @param data * @param data
* @param id * @param id
* @param updateColomn * @param filterValue
* @param option
* @return the affected rows. * @return the affected rows.
* @throws Exception */ * @throws Exception */
public <T, ID_TYPE> long update( public <T, ID_TYPE> long update(
@ -301,7 +300,8 @@ public abstract class DBAccess implements Closeable {
/** 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). /** 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 clazz Data model that might remove element.
* @param option (Optional) Options of the request. * @param condition Condition to remove elements.
* @param options (Optional) Options of the request.
* @return Number of element that is removed. */ * @return Number of element that is removed. */
public long deleteWhere(final Class<?> clazz, final QueryOption... option) throws Exception { public long deleteWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -14,26 +14,26 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.annotation.CreationTimestamp;
import org.atriasoft.archidata.annotation.UpdateTimestamp;
import org.atriasoft.archidata.dataAccess.addOnMongo.AddOnManyToOne;
import org.atriasoft.archidata.dataAccess.addOnMongo.AddOnOneToMany;
import org.atriasoft.archidata.dataAccess.addOnMongo.DataAccessAddOn;
import org.atriasoft.archidata.dataAccess.options.CheckFunction;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.FilterValue;
import org.atriasoft.archidata.dataAccess.options.Limit;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.OrderBy;
import org.atriasoft.archidata.dataAccess.options.QueryOption;
import org.atriasoft.archidata.db.DbIoMorphia;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.UuidUtils;
import org.bson.Document; import org.bson.Document;
import org.bson.conversions.Bson; import org.bson.conversions.Bson;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
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.OptionSpecifyType;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -14,43 +14,37 @@ import java.sql.Types;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.annotation.CreationTimestamp;
import org.atriasoft.archidata.annotation.UpdateTimestamp;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToMany;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToManyLocal;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnManyToOne;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnOneToMany;
import org.atriasoft.archidata.dataAccess.addOnSQL.DataAccessAddOn;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.CheckFunction;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.DBInterfaceRoot;
import org.atriasoft.archidata.dataAccess.options.FilterValue;
import org.atriasoft.archidata.dataAccess.options.GroupBy;
import org.atriasoft.archidata.dataAccess.options.Limit;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.OrderBy;
import org.atriasoft.archidata.dataAccess.options.QueryOption;
import org.atriasoft.archidata.dataAccess.options.ReadAllColumn;
import org.atriasoft.archidata.dataAccess.options.TransmitKey;
import org.atriasoft.archidata.db.DbIoSql;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.DateTools;
import org.atriasoft.archidata.tools.UuidUtils;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToOne;
import org.kar.archidata.dataAccess.addOnSQL.AddOnOneToMany;
import org.kar.archidata.dataAccess.addOnSQL.DataAccessAddOn;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.DBInterfaceRoot;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.GroupBy;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.dataAccess.options.TransmitKey;
import org.kar.archidata.db.DbIoSql;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.DateTools;
import org.kar.archidata.tools.UuidUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -67,12 +61,8 @@ import jakarta.ws.rs.InternalServerErrorException;
public class DBAccessSQL extends DBAccess { public class DBAccessSQL extends DBAccess {
final static Logger LOGGER = LoggerFactory.getLogger(DBAccessSQL.class); final static Logger LOGGER = LoggerFactory.getLogger(DBAccessSQL.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...) // by default we manage some add-on that permit to manage non-native model (like json serialization, List of external key as String list...)
final static List<DataAccessAddOn> addOn = List.of(// final static List<DataAccessAddOn> addOn = List.of(new AddOnManyToMany(), new AddOnManyToOne(),
new AddOnManyToMany(), // new AddOnOneToMany(), new AddOnDataJson());
new AddOnManyToOne(), //
new AddOnOneToMany(), //
new AddOnDataJson(), //
new AddOnManyToManyLocal());
private final DbIoSql db; private final DbIoSql db;
@ -380,18 +370,7 @@ public class DBAccessSQL extends DBAccess {
if (tmp == null) { if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER); ps.setNull(iii.value, Types.INTEGER);
} else { } else {
final OffsetDateTime offsetDateTime = ((Date) tmp).toInstant().atZone(ZoneId.systemDefault()) final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant());
.toOffsetDateTime();
final Timestamp sqlDate = java.sql.Timestamp
.from(offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC).toInstant());
ps.setTimestamp(iii.value, sqlDate);
}
} else if (type == OffsetDateTime.class) {
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final Timestamp sqlDate = java.sql.Timestamp
.from(((OffsetDateTime) tmp).withOffsetSameInstant(ZoneOffset.UTC).toInstant());
ps.setTimestamp(iii.value, sqlDate); ps.setTimestamp(iii.value, sqlDate);
} }
} else if (type == Instant.class) { } else if (type == Instant.class) {
@ -543,9 +522,7 @@ public class DBAccessSQL extends DBAccess {
if (rs.wasNull()) { if (rs.wasNull()) {
field.set(data, null); field.set(data, null);
} else { } else {
final OffsetDateTime odt = tmp.toInstant().atOffset(ZoneOffset.UTC); field.set(data, Date.from(tmp.toInstant()));
odt.atZoneSameInstant(ZoneId.systemDefault());
field.set(data, Date.from(odt.toInstant()));
countNotNull.inc(); countNotNull.inc();
} }
} catch (final SQLException ex) { } catch (final SQLException ex) {
@ -560,28 +537,6 @@ public class DBAccessSQL extends DBAccess {
countNotNull.inc(); countNotNull.inc();
} }
} }
} else if (type == OffsetDateTime.class) {
try {
final Timestamp tmp = rs.getTimestamp(count.value);
if (rs.wasNull()) {
field.set(data, null);
} else {
final OffsetDateTime odt = tmp.toInstant().atOffset(ZoneOffset.UTC);
field.set(data, odt);
countNotNull.inc();
}
} catch (final SQLException ex) {
final String tmp = rs.getString(count.value);
LOGGER.error("Fail to parse the SQL time !!! {}", tmp);
if (rs.wasNull()) {
field.set(data, null);
} else {
final OffsetDateTime date = DateTools.parseOffsetDateTime(tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", date);
field.set(data, date);
countNotNull.inc();
}
}
} else if (type == Instant.class) { } else if (type == Instant.class) {
final String tmp = rs.getString(count.value); final String tmp = rs.getString(count.value);
if (rs.wasNull()) { if (rs.wasNull()) {
@ -948,13 +903,11 @@ public class DBAccessSQL extends DBAccess {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(field); final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null) { if (addOn != null && !addOn.canInsert(field)) {
if (addOn.isInsertAsync(field)) { if (addOn.isInsertAsync(field)) {
asyncFieldUpdate.add(field); asyncFieldUpdate.add(field);
} }
if (!addOn.canInsert(field)) { continue;
continue;
}
} }
final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
if (createTime) { if (createTime) {
@ -1166,31 +1119,6 @@ public class DBAccessSQL extends DBAccess {
query.append("UPDATE `"); query.append("UPDATE `");
query.append(tableName); query.append(tableName);
query.append("` SET "); query.append("` SET ");
//Some mode need to get the previous data to perform a correct update...
boolean needPreviousValues = false;
for (final Field field : clazz.getFields()) {
// field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final FieldName name = AnnotationTools.getFieldName(field, options);
if (!filter.getValues().contains(name.inStruct())) {
continue;
} else if (AnnotationTools.isGenericField(field)) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null && addOn.isPreviousDataNeeded(field)) {
needPreviousValues = true;
break;
}
}
Object previousData = null;
if (needPreviousValues) {
final List<TransmitKey> transmitKey = options.get(TransmitKey.class);
previousData = this.get(data.getClass(), transmitKey.get(0).getKey(), new AccessDeletedItems(),
new ReadAllColumn());
}
boolean firstField = true; boolean firstField = true;
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
@ -1205,19 +1133,17 @@ public class DBAccessSQL extends DBAccess {
continue; continue;
} }
final DataAccessAddOn addOn = findAddOnforField(field); final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null) { if (addOn != null && !addOn.canInsert(field)) {
if (addOn.isUpdateAsync(field)) { if (addOn.isInsertAsync(field)) {
final List<TransmitKey> transmitKey = options.get(TransmitKey.class); final List<TransmitKey> transmitKey = options.get(TransmitKey.class);
if (transmitKey.size() != 1) { if (transmitKey.size() != 1) {
throw new DataAccessException( throw new DataAccessException(
"Fail to transmit Key to update the async update... (must have only 1)"); "Fail to transmit Key to update the async update... (must have only 1)");
} }
addOn.asyncUpdate(this, previousData, tableName, transmitKey.get(0).getKey(), field, addOn.asyncUpdate(this, tableName, transmitKey.get(0).getKey(), field, field.get(data),
field.get(data), asyncActions, options); asyncActions, options);
}
if (!addOn.canInsert(field)) {
continue;
} }
continue;
} }
if (!field.getClass().isPrimitive()) { if (!field.getClass().isPrimitive()) {
final Object tmp = field.get(data); final Object tmp = field.get(data);
@ -1242,6 +1168,7 @@ public class DBAccessSQL extends DBAccess {
query.append(" "); query.append(" ");
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
condition.whereAppendQuery(query, tableName, null, deletedFieldName); condition.whereAppendQuery(query, tableName, null, deletedFieldName);
// If the first field is not set, then nothing to update n the main base: // If the first field is not set, then nothing to update n the main base:
if (!firstField) { if (!firstField) {
LOGGER.debug("generate update query: '{}'", query.toString()); LOGGER.debug("generate update query: '{}'", query.toString());
@ -1277,9 +1204,6 @@ public class DBAccessSQL extends DBAccess {
addOn.insertData(this, ps, field, data, iii); addOn.insertData(this, ps, field, data, iii);
} }
} }
for (final LazyGetter action : asyncActions) {
action.doRequest();
}
condition.injectQuery(this, ps, iii); condition.injectQuery(this, ps, iii);
final int out = ps.executeUpdate(); final int out = ps.executeUpdate();
return out; return out;
@ -1288,6 +1212,9 @@ public class DBAccessSQL extends DBAccess {
} catch (final SQLException ex) { } catch (final SQLException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
for (final LazyGetter action : asyncActions) {
action.doRequest();
}
return 0L; return 0L;
} }
@ -1458,7 +1385,7 @@ public class DBAccessSQL extends DBAccess {
final T out = (T) data; final T out = (T) data;
outs.add(out); outs.add(out);
} }
LOGGER.trace("Async calls: {}", lazyCall.size()); LOGGER.info("Async calls: {}", lazyCall.size());
for (final LazyGetter elem : lazyCall) { for (final LazyGetter elem : lazyCall) {
elem.doRequest(); elem.doRequest();
} }

View File

@ -1,11 +1,11 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.QueryOption; import org.kar.archidata.dataAccess.options.QueryOption;
import org.atriasoft.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -111,6 +111,12 @@ public class DataAccess {
} }
} }
/** @param <T>
* @param data
* @param id
* @param filterValue
* @return the affected rows.
* @throws Exception */
public static <T, ID_TYPE> long update( public static <T, ID_TYPE> long update(
final T data, final T data,
final ID_TYPE id, final ID_TYPE id,
@ -219,6 +225,7 @@ public class DataAccess {
/** 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). /** 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 clazz Data model that might remove element.
* @param condition Condition to remove elements.
* @param options (Optional) Options of the request. * @param options (Optional) Options of the request.
* @return Number of element that is removed. */ * @return Number of element that is removed. */
public static long deleteWhere(final Class<?> clazz, final QueryOption... options) throws Exception { public static long deleteWhere(final Class<?> clazz, final QueryOption... options) throws Exception {

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.io.IOException; import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -16,16 +16,16 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.dataAccess.exportTools.TableQuery; import org.kar.archidata.dataAccess.exportTools.TableQuery;
import org.atriasoft.archidata.dataAccess.exportTools.TableQueryTypes; import org.kar.archidata.dataAccess.exportTools.TableQueryTypes;
import org.atriasoft.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.GroupBy; import org.kar.archidata.dataAccess.options.GroupBy;
import org.atriasoft.archidata.dataAccess.options.Limit; import org.kar.archidata.dataAccess.options.Limit;
import org.atriasoft.archidata.dataAccess.options.OrderBy; import org.kar.archidata.dataAccess.options.OrderBy;
import org.atriasoft.archidata.dataAccess.options.QueryOption; import org.kar.archidata.dataAccess.options.QueryOption;
import org.atriasoft.archidata.exception.DataAccessException; import org.kar.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ContextGenericTools; import org.kar.archidata.tools.ContextGenericTools;
import org.atriasoft.archidata.tools.DateTools; import org.kar.archidata.tools.DateTools;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.sql.Timestamp; import java.sql.Timestamp;
@ -10,16 +10,16 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.CreationTimestamp;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.UpdateTimestamp;
import org.atriasoft.archidata.dataAccess.addOnSQL.DataAccessAddOn;
import org.atriasoft.archidata.dataAccess.options.CreateDropTable;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.bson.types.ObjectId; 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; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
// Mark as deprecated while the concept is not ready ... // Mark as deprecated while the concept is not ready ...
@Deprecated @Deprecated

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
public interface LazyGetter { public interface LazyGetter {
void doRequest() throws Exception; void doRequest() throws Exception;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.ArrayList; import java.util.ArrayList;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.List; import java.util.List;

View File

@ -1,12 +1,12 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems; import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.CreateDropTable; import org.kar.archidata.dataAccess.options.CreateDropTable;
import org.atriasoft.archidata.dataAccess.options.QueryOption; import org.kar.archidata.dataAccess.options.QueryOption;
import org.atriasoft.archidata.dataAccess.options.ReadAllColumn; import org.kar.archidata.dataAccess.options.ReadAllColumn;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.util.ArrayList; import java.util.ArrayList;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess; package org.kar.archidata.dataAccess;
import java.sql.ResultSet; import java.sql.ResultSet;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess.addOnMongo; package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
@ -6,23 +6,23 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.dataAccess.CountInOut;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DBAccessMorphia;
import org.atriasoft.archidata.dataAccess.DataFactory;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryAnd;
import org.atriasoft.archidata.dataAccess.QueryCondition;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.addOnSQL.model.LinkTableGeneric;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.bson.Document; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,17 +1,17 @@
package org.atriasoft.archidata.dataAccess.addOnMongo; package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.dataAccess.DBAccessMorphia;
import org.atriasoft.archidata.dataAccess.DataFactory;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.bson.Document; import org.bson.Document;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess.addOnMongo; package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
@ -6,15 +6,15 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.dataAccess.DBAccessMorphia;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryCondition;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.bson.Document; import org.bson.Document;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
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.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,13 +1,13 @@
package org.atriasoft.archidata.dataAccess.addOnMongo; package org.kar.archidata.dataAccess.addOnMongo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.dataAccess.DBAccessMorphia;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.bson.Document; import org.bson.Document;
import org.kar.archidata.dataAccess.DBAccessMorphia;
import org.kar.archidata.dataAccess.LazyGetter;
import org.kar.archidata.dataAccess.QueryOptions;
public interface DataAccessAddOn { public interface DataAccessAddOn {
/** Get the Class of the declaration annotation /** Get the Class of the declaration annotation
@ -26,6 +26,12 @@ public interface DataAccessAddOn {
* @return True of the field is manage by the current Add-on. */ * @return True of the field is manage by the current Add-on. */
boolean isCompatibleField(Field elem); 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( void insertData(
final DBAccessMorphia ioDb, final DBAccessMorphia ioDb,
final Field field, final Field field,
@ -59,7 +65,14 @@ public interface DataAccessAddOn {
throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; throws Exception, SQLException, IllegalArgumentException, IllegalAccessException;
/** Create associated table of the specific element. /** Create associated table of the specific element.
*/ * @param tableName
* @param elem
* @param mainTableBuilder
* @param ListOtherTables
* @param createIfNotExist
* @param createDrop
* @param fieldId
* @throws Exception */
void createTables( void createTables(
String tableName, String tableName,
final Field primaryField, final Field primaryField,

View File

@ -1,4 +1,4 @@
package org.atriasoft.archidata.dataAccess.addOnSQL; package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
@ -10,22 +10,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.dataAccess.CountInOut;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DBAccessSQL;
import org.atriasoft.archidata.dataAccess.DataFactory;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.addOnSQL.model.TableCoversGeneric;
import org.atriasoft.archidata.dataAccess.options.OptionRenameColumn;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ContextGenericTools;
import org.bson.types.ObjectId; 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.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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -219,63 +219,62 @@ public class AddOnDataJson implements DataAccessAddOn {
public static void addLink( public static void addLink(
final DBAccess ioDb, final DBAccess ioDb,
final Class<?> clazz, final Class<?> clazz,
String clazzPrimaryKeyName, final String clazzPrimaryKeyName,
final Object clazzPrimaryKeyValue, final Object clazzPrimaryKeyValue,
final String fieldNameToUpdate, final String fieldNameToUpdate,
final Object valueToAdd) throws Exception { final Object valueToAdd) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName), final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("idOfTheObject", clazzPrimaryKeyValue.getClass()), new OptionSpecifyType("id", clazzPrimaryKeyValue.getClass()),
new OptionSpecifyType("filedNameOfTheObject", valueToAdd.getClass(), true)); new OptionSpecifyType("covers", valueToAdd.getClass(), true));
if (clazzPrimaryKeyName == null) { if (clazzPrimaryKeyName != null && !clazzPrimaryKeyName.equals("id")) {
clazzPrimaryKeyName = "id"; options.add(new OptionRenameColumn("id", clazzPrimaryKeyName));
}
if (fieldNameToUpdate != null && !fieldNameToUpdate.equals("covers")) {
options.add(new OptionRenameColumn("covers", fieldNameToUpdate));
} }
options.add(new OptionRenameColumn("idOfTheObject", clazzPrimaryKeyName));
options.add(new OptionRenameColumn("filedNameOfTheObject", fieldNameToUpdate));
final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray()); final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray());
if (data.filedNameOfTheObject == null) { if (data.covers == null) {
data.filedNameOfTheObject = new ArrayList<>(); data.covers = new ArrayList<>();
} }
for (final Object elem : data.filedNameOfTheObject) { for (final Object elem : data.covers) {
if (elem.equals(valueToAdd)) { if (elem.equals(valueToAdd)) {
return; return;
} }
} }
data.filedNameOfTheObject.add(valueToAdd); data.covers.add(valueToAdd);
ioDb.update(data, data.idOfTheObject, List.of("filedNameOfTheObject"), options.getAllArray()); ioDb.update(data, data.id, List.of("covers"), options.getAllArray());
} }
public static void removeLink( public static void removeLink(
final DBAccess ioDb, final DBAccess ioDb,
final Class<?> clazz, final Class<?> clazz,
String clazzPrimaryKeyName, final String clazzPrimaryKeyName,
final Object clazzPrimaryKeyValue, final Object clazzPrimaryKeyValue,
final String fieldNameToUpdate, final String fieldNameToUpdate,
final Object valueToRemove) throws Exception { final Object valueToRemove) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz); final String tableName = AnnotationTools.getTableName(clazz);
final QueryOptions options = new QueryOptions(new OverrideTableName(tableName), final QueryOptions options = new QueryOptions(new OverrideTableName(tableName),
new OptionSpecifyType("idOfTheObject", clazzPrimaryKeyValue.getClass()), new OptionSpecifyType("id", clazzPrimaryKeyValue.getClass()),
new OptionSpecifyType("filedNameOfTheObject", valueToRemove.getClass(), true)); new OptionSpecifyType("covers", valueToRemove.getClass(), true));
if (clazzPrimaryKeyName == null) { if (clazzPrimaryKeyName != null && !clazzPrimaryKeyName.equals("id")) {
clazzPrimaryKeyName = "id"; options.add(new OptionRenameColumn("id", clazzPrimaryKeyName));
}
if (fieldNameToUpdate != null && !fieldNameToUpdate.equals("covers")) {
options.add(new OptionRenameColumn("covers", fieldNameToUpdate));
} }
options.add(new OptionRenameColumn("idOfTheObject", clazzPrimaryKeyName));
options.add(new OptionRenameColumn("filedNameOfTheObject", fieldNameToUpdate));
final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray()); final TableCoversGeneric data = ioDb.get(TableCoversGeneric.class, clazzPrimaryKeyValue, options.getAllArray());
if (data.filedNameOfTheObject == null) { if (data.covers == null) {
return; return;
} }
final List<Object> newList = new ArrayList<>(); final List<Object> newList = new ArrayList<>();
for (final Object elem : data.filedNameOfTheObject) { for (final Object elem : data.covers) {
if (elem.equals(valueToRemove)) { if (elem.equals(valueToRemove)) {
continue; continue;
} }
newList.add(elem); newList.add(elem);
} }
data.filedNameOfTheObject = newList; data.covers = newList;
if (data.filedNameOfTheObject.isEmpty()) { ioDb.update(data, data.id, List.of("covers"), options.getAllArray());
data.filedNameOfTheObject = null;
}
ioDb.update(data, data.idOfTheObject, List.of("filedNameOfTheObject"), options.getAllArray());
} }
} }

View File

@ -1,9 +1,7 @@
package org.atriasoft.archidata.dataAccess.addOnSQL; package org.kar.archidata.dataAccess.addOnSQL;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@ -11,26 +9,25 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.atriasoft.archidata.annotation.AnnotationTools;
import org.atriasoft.archidata.annotation.AnnotationTools.FieldName;
import org.atriasoft.archidata.dataAccess.CountInOut;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DBAccessMorphia;
import org.atriasoft.archidata.dataAccess.DBAccessSQL;
import org.atriasoft.archidata.dataAccess.DataFactory;
import org.atriasoft.archidata.dataAccess.LazyGetter;
import org.atriasoft.archidata.dataAccess.QueryAnd;
import org.atriasoft.archidata.dataAccess.QueryCondition;
import org.atriasoft.archidata.dataAccess.QueryInList;
import org.atriasoft.archidata.dataAccess.QueryOptions;
import org.atriasoft.archidata.dataAccess.addOnSQL.model.LinkTableGeneric;
import org.atriasoft.archidata.dataAccess.options.Condition;
import org.atriasoft.archidata.dataAccess.options.OptionSpecifyType;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.exception.SystemException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -89,102 +86,20 @@ public class AddOnManyToMany implements DataAccessAddOn {
return false; return false;
} }
public static String hashTo64Chars(final String input) { public static String generateLinkTableNameField(
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
final byte[] hash = digest.digest(input.getBytes());
final StringBuilder hexString = new StringBuilder();
for (final byte b : hash) {
final String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString().substring(0, 64);
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException("Erreur lors du hachage de la chaîne", e);
}
}
public static String hashIfNeeded(final String input) {
if (input.length() > 64) {
// Keep only the 50 first chars
final String truncated = input.substring(0, Math.min(input.length(), 50));
final String fullHash = hashTo64Chars(input);
final String hashPart = fullHash.substring(0, 14);
return truncated + hashPart;
}
return input;
}
public record LinkTableWithMode(
String tableName,
boolean first,
boolean equals) {}
public static LinkTableWithMode generateLinkTableNameField(
final String tableName, final String tableName,
final Field field, final Field field,
final QueryOptions options) throws Exception { final QueryOptions options) throws Exception {
return generateLinkTableName(tableName, field); final FieldName name = AnnotationTools.getFieldName(field, options);
return generateLinkTableName(tableName, name.inTable());
} }
public static LinkTableWithMode generateLinkTableName( public static String generateLinkTableName(final String tableName, final String name) {
final String tableAName, String localName = name;
final String tableAFieldName, if (name.endsWith("s")) {
final String tableBName, localName = name.substring(0, name.length() - 1);
final String tableBFieldName) {
final String concatElementA = tableAName + "_" + tableAFieldName;
final String concatElementB = tableBName + "_" + tableBFieldName;
final int compareResult = concatElementA.compareTo(concatElementB);
if (compareResult == 0) {
return new LinkTableWithMode(hashIfNeeded(concatElementA + "_autolink"), true, true);
} }
if (compareResult < 0) { return tableName + "_link_" + localName;
return new LinkTableWithMode(hashIfNeeded(concatElementA + "_link_" + concatElementB), true, false);
}
return new LinkTableWithMode(hashIfNeeded(concatElementB + "_link_" + concatElementA), false, false);
}
public static LinkTableWithMode generateLinkTableName(
final String tableAName,
final String tableAFieldName,
final ManyToMany manyToMany) throws SystemException {
if (manyToMany == null) {
throw new SystemException("@ManyMany is a null pointer " + tableAName);
}
if (manyToMany.targetEntity() == null) {
throw new SystemException("@ManyMany target entity is a null pointer: " + tableAName);
}
if (manyToMany.mappedBy() == null || manyToMany.mappedBy().isEmpty()) {
throw new SystemException("@ManyMany mapped by is not defined: " + tableAName);
}
final String tableNameRemote = AnnotationTools.getTableName(manyToMany.targetEntity());
return generateLinkTableName(tableAName, tableAFieldName, tableNameRemote, manyToMany.mappedBy());
}
public static LinkTableWithMode generateLinkTableName(final String tableAName, final Field field)
throws SystemException {
if (field == null) {
// TODO: throw !!!!
}
final FieldName columnName = AnnotationTools.getFieldName(field, null);
final ManyToMany manyToMany = AnnotationTools.get(field, ManyToMany.class);
return generateLinkTableName(tableAName, columnName.inTable(), manyToMany);
}
public static LinkTableWithMode generateLinkTableName(final Class<?> clazz, final String fieldName)
throws SystemException {
if (clazz == null) {
throw new SystemException("@ManyMany class reference is a null pointer ");
}
if (fieldName == null || fieldName.isEmpty() || fieldName.isBlank()) {
throw new SystemException("@ManyMany field of class reference is not defined");
}
final String tableName = AnnotationTools.getTableName(clazz);
final Field requestedField = AnnotationTools.getFieldNamed(clazz, fieldName);
return generateLinkTableName(tableName, requestedField);
} }
public void generateConcatQuery( public void generateConcatQuery(
@ -197,13 +112,18 @@ public class AddOnManyToMany implements DataAccessAddOn {
@NotNull final CountInOut count, @NotNull final CountInOut count,
final QueryOptions options) throws Exception { final QueryOptions options) throws Exception {
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field); final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
final LinkTableWithMode linkTable = generateLinkTableName(tableName, name, manyToMany); 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()) final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]; .getActualTypeArguments()[0];
final String tmpVariable = "tmp_" + Integer.toString(count.value); final String tmpVariable = "tmp_" + Integer.toString(count.value);
querySelect.append(" (SELECT GROUP_CONCAT("); querySelect.append(" (SELECT GROUP_CONCAT(");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
if (linkTable.first()) { if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append(".object2Id "); querySelect.append(".object2Id ");
} else { } else {
querySelect.append(".object1Id "); querySelect.append(".object1Id ");
@ -227,7 +147,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
} }
} }
querySelect.append("') FROM "); querySelect.append("') FROM ");
querySelect.append(linkTable.tableName()); querySelect.append(linkTableName);
querySelect.append(" "); querySelect.append(" ");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
querySelect.append(" WHERE "); querySelect.append(" WHERE ");
@ -240,7 +160,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
querySelect.append(" = "); querySelect.append(" = ");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
querySelect.append("."); querySelect.append(".");
if (linkTable.first()) { if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append("object1Id "); querySelect.append("object1Id ");
} else { } else {
querySelect.append("object2Id "); querySelect.append("object2Id ");
@ -248,7 +168,7 @@ public class AddOnManyToMany implements DataAccessAddOn {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) { if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
querySelect.append(" GROUP BY "); querySelect.append(" GROUP BY ");
querySelect.append(tmpVariable); querySelect.append(tmpVariable);
if (linkTable.first()) { if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) {
querySelect.append(".object1Id"); querySelect.append(".object1Id");
} else { } else {
querySelect.append(".object2Id"); querySelect.append(".object2Id");
@ -304,7 +224,8 @@ public class AddOnManyToMany implements DataAccessAddOn {
final QueryOptions options, final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception { final List<LazyGetter> lazyCall) throws Exception {
if (field.getType() != List.class) { if (field.getType() != List.class) {
throw new SystemException("@ManyToMany must contain a List"); LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName());
return;
} }
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType()) final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]; .getActualTypeArguments()[0];
@ -313,14 +234,12 @@ public class AddOnManyToMany implements DataAccessAddOn {
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
return; return;
} } else if (objectClass == UUID.class) {
if (objectClass == UUID.class) {
final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value); final List<UUID> idList = ioDb.getListOfRawUUIDs(rs, count.value);
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
return; return;
} } else if (objectClass == ObjectId.class) {
if (objectClass == ObjectId.class) {
final List<ObjectId> idList = ioDb.getListOfRawOIDs(rs, count.value); final List<ObjectId> idList = ioDb.getListOfRawOIDs(rs, count.value);
field.set(data, idList); field.set(data, idList);
count.inc(); count.inc();
@ -409,7 +328,6 @@ public class AddOnManyToMany implements DataAccessAddOn {
@Override @Override
public void asyncUpdate( public void asyncUpdate(
final DBAccessSQL ioDb, final DBAccessSQL ioDb,
final Object previousData,
final String tableName, final String tableName,
final Object localKey, final Object localKey,
final Field field, final Field field,
@ -427,14 +345,14 @@ public class AddOnManyToMany implements DataAccessAddOn {
"Can not ManyToMany with other than List<Long> or List<UUID> or List<ObjectId> Model: List<" "Can not ManyToMany with other than List<Long> or List<UUID> or List<ObjectId> Model: List<"
+ objectClass.getCanonicalName() + ">"); + objectClass.getCanonicalName() + ">");
} }
final LinkTableWithMode linkTable = generateLinkTableName(tableName, field); final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String obj1 = linkTable.first ? "object1Id" : "object2Id"; final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
final String obj2 = linkTable.first ? "object2Id" : "object1Id";
actions.add(() -> { actions.add(() -> {
ioDb.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTable.tableName()), ioDb.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTableName),
new Condition(new QueryCondition(obj1, "=", localKey)), new Condition(new QueryCondition("object1Id", "=", localKey)),
new OptionSpecifyType(obj1, localKey.getClass()), new OptionSpecifyType(obj2, objectClass)); new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", objectClass));
}); });
asyncInsert(ioDb, tableName, localKey, field, data, actions, options); asyncInsert(ioDb, tableName, localKey, field, data, actions, options);
} }
@ -467,47 +385,45 @@ public class AddOnManyToMany implements DataAccessAddOn {
"Can not ManyToMany with other than List<Long> or List<UUID> or List<ObjectId> Model: List<" "Can not ManyToMany with other than List<Long> or List<UUID> or List<ObjectId> Model: List<"
+ objectClass.getCanonicalName() + ">"); + objectClass.getCanonicalName() + ">");
} }
final LinkTableWithMode linkTable = generateLinkTableName(tableName, field); final FieldName columnName = AnnotationTools.getFieldName(field, options);
final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final List<Object> dataCasted = (List<Object>) data; final List<Object> dataCasted = (List<Object>) data;
if (dataCasted.size() == 0) { if (dataCasted.size() == 0) {
return; return;
} }
final String obj1 = linkTable.first ? "object1Id" : "object2Id";
final String obj2 = linkTable.first ? "object2Id" : "object1Id";
final List<LinkTableGeneric> insertElements = new ArrayList<>(); final List<LinkTableGeneric> insertElements = new ArrayList<>();
for (final Object remoteKey : dataCasted) { for (final Object remoteKey : dataCasted) {
if (remoteKey == null) { if (remoteKey == null) {
throw new DataAccessException("Try to insert remote key with null value"); throw new DataAccessException("Try to insert remote key with null value");
} }
if (linkTable.first) { insertElements.add(new LinkTableGeneric(localKey, remoteKey));
insertElements.add(new LinkTableGeneric(localKey, remoteKey));
} else {
insertElements.add(new LinkTableGeneric(remoteKey, localKey));
}
} }
if (insertElements.size() == 0) { if (insertElements.size() == 0) {
LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted);
return; return;
} }
actions.add(() -> { actions.add(() -> {
ioDb.insertMultiple(insertElements, new OverrideTableName(linkTable.tableName()), ioDb.insertMultiple(insertElements, new OverrideTableName(linkTableName),
new OptionSpecifyType(obj1, localKey.getClass()), new OptionSpecifyType(obj2, objectClass)); new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType("object2Id", objectClass));
}); });
} }
@Override @Override
public void drop(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options) public void drop(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception { throws Exception {
final LinkTableWithMode linkTable = generateLinkTableName(tableName, field); final FieldName columnName = AnnotationTools.getFieldName(field, options);
ioDb.drop(LinkTableGeneric.class, new OverrideTableName(linkTable.tableName())); final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
ioDb.drop(LinkTableGeneric.class, new OverrideTableName(linkTableName));
} }
@Override @Override
public void cleanAll(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options) public void cleanAll(final DBAccessSQL ioDb, final String tableName, final Field field, final QueryOptions options)
throws Exception { throws Exception {
final LinkTableWithMode linkTable = generateLinkTableName(tableName, field); final FieldName columnName = AnnotationTools.getFieldName(field, options);
ioDb.cleanAll(LinkTableGeneric.class, new OverrideTableName(linkTable.tableName())); final String linkTableName = generateLinkTableName(tableName, columnName.inTable());
ioDb.cleanAll(LinkTableGeneric.class, new OverrideTableName(linkTableName));
} }
public static void addLink( public static void addLink(
@ -517,19 +433,18 @@ public class AddOnManyToMany implements DataAccessAddOn {
final String column, final String column,
final Object remoteKey) throws Exception { final Object remoteKey) throws Exception {
if (ioDb instanceof final DBAccessSQL daSQL) { if (ioDb instanceof final DBAccessSQL daSQL) {
final LinkTableWithMode linkTable = generateLinkTableName(clazz, column); final String tableName = AnnotationTools.getTableName(clazz);
final LinkTableGeneric insertElement = linkTable.first ? new LinkTableGeneric(localKey, remoteKey) final String linkTableName = generateLinkTableName(tableName, column);
: new LinkTableGeneric(remoteKey, localKey); final LinkTableGeneric insertElement = new LinkTableGeneric(localKey, remoteKey);
final String obj1 = linkTable.first ? "object1Id" : "object2Id"; daSQL.insert(insertElement, new OverrideTableName(linkTableName),
final String obj2 = linkTable.first ? "object2Id" : "object1Id"; new OptionSpecifyType("object1Id", localKey.getClass()),
daSQL.insert(insertElement, new OverrideTableName(linkTable.tableName()), new OptionSpecifyType("object2Id", remoteKey.getClass()));
new OptionSpecifyType(obj1, localKey.getClass()),
new OptionSpecifyType(obj2, remoteKey.getClass()));
} else if (ioDb instanceof final DBAccessMorphia dam) { } else if (ioDb instanceof final DBAccessMorphia dam) {
} else { } else {
throw new DataAccessException("DataAccess Not managed"); throw new DataAccessException("DataAccess Not managed");
} }
} }
public static long removeLink( public static long removeLink(
@ -539,14 +454,13 @@ public class AddOnManyToMany implements DataAccessAddOn {
final String column, final String column,
final Object remoteKey) throws Exception { final Object remoteKey) throws Exception {
if (ioDb instanceof final DBAccessSQL daSQL) { if (ioDb instanceof final DBAccessSQL daSQL) {
final LinkTableWithMode linkTable = generateLinkTableName(clazz, column); final String tableName = AnnotationTools.getTableName(clazz);
final String obj1 = linkTable.first ? "object1Id" : "object2Id"; final String linkTableName = generateLinkTableName(tableName, column);
final String obj2 = linkTable.first ? "object2Id" : "object1Id"; return daSQL.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTableName),
return daSQL.deleteWhere(LinkTableGeneric.class, new OverrideTableName(linkTable.tableName()), new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey),
new Condition(new QueryAnd(new QueryCondition(obj1, "=", localKey), new QueryCondition("object2Id", "=", remoteKey))),
new QueryCondition(obj2, "=", remoteKey))), new OptionSpecifyType("object1Id", localKey.getClass()),
new OptionSpecifyType(obj1, localKey.getClass()), new OptionSpecifyType("object2Id", remoteKey.getClass()));
new OptionSpecifyType(obj2, remoteKey.getClass()));
} else if (ioDb instanceof final DBAccessMorphia dam) { } else if (ioDb instanceof final DBAccessMorphia dam) {
return 0L; return 0L;
} else { } else {
@ -554,8 +468,6 @@ public class AddOnManyToMany implements DataAccessAddOn {
} }
} }
private static List<String> tableAlreadyCreated = new ArrayList<>();
@Override @Override
public void createTables( public void createTables(
final String tableName, final String tableName,
@ -569,21 +481,18 @@ public class AddOnManyToMany implements DataAccessAddOn {
final int fieldId, final int fieldId,
final QueryOptions options) throws Exception { final QueryOptions options) throws Exception {
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field); final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
if (manyToMany.mappedBy() == null || manyToMany.mappedBy().length() == 0) { if (manyToMany.mappedBy() != null && manyToMany.mappedBy().length() != 0) {
throw new SystemException("MappedBy must be set in ManyMany: " + tableName + " " + field.getName()); // not the reference model to create base:
} return;
final LinkTableWithMode linkTable = generateLinkTableNameField(tableName, field, options);
if (linkTable.first() || linkTable.equals()) {
final QueryOptions options2 = new QueryOptions(new OverrideTableName(linkTable.tableName()));
final Class<?> objectClass = (Class<?>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
final Class<?> primaryType = primaryField.getType();
final String obj1 = linkTable.first ? "object1Id" : "object2Id";
final String obj2 = linkTable.first ? "object2Id" : "object1Id";
options2.add(new OptionSpecifyType(obj1, primaryType));
options2.add(new OptionSpecifyType(obj2, objectClass));
final List<String> sqlCommand = DataFactory.createTable(LinkTableGeneric.class, options2);
postActionList.addAll(sqlCommand);
} }
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);
} }
} }

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