[DEV] review many models and system

This commit is contained in:
Edouard DUPIN 2023-10-14 12:18:36 +02:00
parent 99cca8bebf
commit d8c6de7bde
79 changed files with 3367 additions and 2996 deletions

7
.checkstyle Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
<fileset name="all" enabled="true" check-config-name="Google Checks" local="false">
<file-match-pattern match-pattern="." include-pattern="true"/>
</fileset>
</fileset-config>

View File

@ -8,36 +8,20 @@
</classpathentry>
<classpathentry kind="src" output="out/maven/test-classes" path="test/src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="out/maven/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="out/maven/test-classes" path="out/maven/generated-test-sources/test-annotations">
<classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="out/maven/classes"/>

1
conditioningUnit Normal file
View File

@ -0,0 +1 @@
[]

13
pom.xml
View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.3.8</version>
<version>0.4.0</version>
<properties>
<jersey.version>3.1.1</jersey.version>
<jaxb.version>2.3.1</jaxb.version>
@ -130,6 +130,17 @@
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.30</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<build>

View File

@ -16,3 +16,4 @@ public class GlobalConfiguration {
ConfigBaseVariable.getDBKeepConnected());
}
}

View File

@ -5,14 +5,15 @@ import org.kar.archidata.util.JWTWrapper;
public class UpdateJwtPublicKey extends Thread {
boolean kill = false;
public void run() {
if (ConfigBaseVariable.getSSOAddress() == null) {
System.out.println("SSO INTERFACE is not provided ==> work alone.");
// No SO provided, kill the thread.
return;
}
while (this.kill == false) {
// need to upgrade when server call us...
while (this.kill == false) {
// need to upgrade when server call us...
try {
JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata");
} catch (Exception e1) {
@ -22,12 +23,13 @@ public class UpdateJwtPublicKey extends Thread {
}
try {
// update every 5 minutes the master token
Thread.sleep(1000*60*5, 0);
Thread.sleep(1000 * 60 * 5, 0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void kill() {
this.kill = true;
}

View File

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

View File

@ -0,0 +1,129 @@
package org.kar.archidata.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Table;
public class AnnotationTools {
static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class);
public static String getTableName(final Class<?> element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @SQLTableName on " + element.getClass().getCanonicalName());
}
final String tmp = ((Table) annotation[0]).name();
if (tmp == null) {
return null;
}
return tmp;
}
public static String getComment(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLComment.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @SQLComment on " + element.getClass().getCanonicalName());
}
final String tmp = ((SQLComment) annotation[0]).value();
if (tmp == null) {
return null;
}
return tmp;
}
public static String getDefault(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLDefault.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @SQLDefault on " + element.getClass().getCanonicalName());
}
final String tmp = ((SQLDefault) annotation[0]).value();
if (tmp == null) {
return null;
}
return tmp;
}
public static Integer getLimitSize(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @SQLLimitSize on " + element.getClass().getCanonicalName());
}
return ((Column) annotation[0]).length();
}
public static boolean isAnnotationGroup(final Field field, final Class<?> annotationType) {
try {
final Annotation[] anns = field.getAnnotations();
for (final Annotation ann : anns) {
if (ann.annotationType() == annotationType) {
return true;
}
}
for (final Annotation ann : anns) {
final Annotation[] anns2 = ann.annotationType().getDeclaredAnnotations();
for (final Annotation ann2 : anns2) {
if (ann2.annotationType() == annotationType) {
return true;
}
}
}
} catch (final Exception ex) {
LOGGER.error("Catch exception when try to get annotation...{}", ex.getLocalizedMessage());
return false;
}
return false;
}
public static boolean getNotNull(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return true;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
return ((Column) annotation[0]).nullable();
}
public static boolean isPrimaryKey(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return true;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
return ((Column) annotation[0]).unique();
}
public static GenerationType getStrategy(final Field element) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
}
return ((GeneratedValue) annotation[0]).strategy();
}
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLCreateTime {
public @interface CreationTimestamp {
}

View File

@ -5,8 +5,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLPrimaryKey {
public @interface SQLAddOn {
}

View File

@ -8,7 +8,7 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLComment {
String value();
}

View File

@ -8,7 +8,7 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDefault {
String value();
}

View File

@ -8,5 +8,5 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDeleted {
}

View File

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

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLLimitSize {
int value();
}

View File

@ -8,5 +8,5 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLNotRead {
}

View File

@ -1,14 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTableName {
String value();
}

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLUpdateTime {
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLAutoIncrement {
public @interface UpdateTimestamp {
}

View File

@ -1,12 +1,15 @@
package org.kar.archidata.annotation;
package org.kar.archidata.annotation.addOn;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.kar.archidata.annotation.SQLAddOn;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLNotNull {
@SQLAddOn
public @interface SQLTableExternalForeinKeyAsList {
}

View File

@ -1,32 +1,28 @@
package org.kar.archidata.annotation;
package org.kar.archidata.annotation.addOn;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.kar.archidata.annotation.SQLAddOn;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTableLinkGeneric {
public static String AUTOMATIC ="__auto__";
public enum ModelLink {
NONE,
INTERNAL, // The list is serialized in a string ',' separated
EXTERNAL // an external table is created and
};
// Permit to select the link mode.
ModelLink value() default ModelLink.EXTERNAL;
// If automatic table name, the table name is: parentTableName_externalTableName__link
@SQLAddOn
public @interface SQLTableExternalLink {
public static String AUTOMATIC = "__auto__";
// If automatic table name, the table name is: parentTableName_externalTableName__link
String tableName() default AUTOMATIC;
// If automatic table name, the name of the foreign table is manage with the variable name.
String externalTableName() default AUTOMATIC;
// If the external link have a field to filter with a specific value (name of the field)
String filterField() default AUTOMATIC;
// If the external link have a field to filter with a specific value (value of the field)
String filterValue() default AUTOMATIC;
}

View File

@ -1,15 +1,14 @@
package org.kar.archidata.annotation.security;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
public @interface DenyAll {
}
@Target({ METHOD })
public @interface DenyAll {}

View File

@ -1,14 +1,14 @@
package org.kar.archidata.annotation.security;
import jakarta.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
public @interface PermitAll {
}
@Target({ METHOD })
public @interface PermitAll {}

View File

@ -1,14 +1,14 @@
package org.kar.archidata.annotation.security;
import jakarta.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
public @interface PermitTokenInURI {
}
@Target({ METHOD })
public @interface PermitTokenInURI {}

View File

@ -1,15 +1,16 @@
package org.kar.archidata.annotation.security;
import jakarta.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
@Target({ METHOD })
public @interface RolesAllowed {
String[] value();
}

View File

@ -1,12 +1,32 @@
package org.kar.archidata.api;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import javax.imageio.ImageIO;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.archidata.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -28,413 +48,376 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.StreamingOutput;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
// https://stackoverflow.com/questions/35367113/jersey-webservice-scalable-approach-to-download-file-and-reply-to-client
// https://gist.github.com/aitoroses/4f7a2b197b732a6a691d
@Path("/data")
@Produces(MediaType.APPLICATION_JSON)
public class DataResource {
static final Logger logger = LoggerFactory.getLogger(MediaType.class);
private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/**
* Upload some datas
*/
private static long tmpFolderId = 1;
private static void createFolder(String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
//Log.print("Create folder: " + path);
Files.createDirectories(java.nio.file.Path.of(path));
}
}
public static long getTmpDataId() {
return tmpFolderId++;
}
public static String getTmpFileInData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static Data getWithSha512(String sha512) {
logger.info("find sha512 = {}", sha512);
try {
return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512);
private static final Logger LOGGER = LoggerFactory.getLogger(MediaType.class);
private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/**
* Upload some datas
*/
private static long tmpFolderId = 1;
private static void createFolder(String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
//Log.print("Create folder: " + path);
Files.createDirectories(java.nio.file.Path.of(path));
}
}
public static long getTmpDataId() {
return tmpFolderId++;
}
public static String getTmpFileInData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static Data getWithSha512(String sha512) {
LOGGER.info("find sha512 = {}", sha512);
try {
return SqlWrapper.getWhere(Data.class, new QuerryCondition("sha512", "=", sha512));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Data getWithId(long id) {
logger.info("find id = {}", id);
try {
return null;
}
public static Data getWithId(long id) {
LOGGER.info("find id = {}", id);
try {
return SqlWrapper.get(Data.class, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException {
// determine mime type:
Data injectedData = new Data();
String mimeType = "";
String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
switch (extension.toLowerCase()) {
case "jpg":
case "jpeg":
mimeType = "image/jpeg";
break;
case "png":
mimeType = "image/png";
break;
case "webp":
mimeType = "image/webp";
break;
case "mka":
mimeType = "audio/x-matroska";
break;
case "mkv":
mimeType = "video/x-matroska";
break;
case "webm":
mimeType = "video/webm";
break;
default:
throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}
injectedData.mimeType = mimeType;
injectedData.sha512 = sha512;
String tmpPath = getTmpFileInData(tmpUID);
injectedData.size = Files.size(Paths.get(tmpPath));
try {
injectedData = SqlWrapper.insert(injectedData);
return null;
}
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException {
// determine mime type:
Data injectedData = new Data();
String mimeType = "";
String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
switch (extension.toLowerCase()) {
case "jpg":
case "jpeg":
mimeType = "image/jpeg";
break;
case "png":
mimeType = "image/png";
break;
case "webp":
mimeType = "image/webp";
break;
case "mka":
mimeType = "audio/x-matroska";
break;
case "mkv":
mimeType = "video/x-matroska";
break;
case "webm":
mimeType = "video/webm";
break;
default:
throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}
injectedData.mimeType = mimeType;
injectedData.sha512 = sha512;
String tmpPath = getTmpFileInData(tmpUID);
injectedData.size = Files.size(Paths.get(tmpPath));
try {
injectedData = SqlWrapper.insert(injectedData);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
String mediaPath = getFileData(injectedData.id);
logger.info("src = {}", tmpPath);
logger.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
logger.info("Move done");
return injectedData;
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
}
public static void removeTemporaryFile(long idData) {
String filepath = DataResource.getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (IOException e) {
logger.info("can not delete temporary file : {}", Paths.get(filepath));
e.printStackTrace();
}
}
}
// save uploaded file to a defined location on the server
static String saveFile(InputStream uploadedInputStream, String serverLocation) {
String out = "";
try {
OutputStream outpuStream = new FileOutputStream(new File(
serverLocation));
int read = 0;
byte[] bytes = new byte[CHUNK_SIZE_IN];
MessageDigest md = MessageDigest.getInstance("SHA-512");
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
//logger.info("write {}", read);
md.update(bytes, 0, read);
outpuStream.write(bytes, 0, read);
}
logger.info("Flush input stream ... {}", serverLocation);
System.out.flush();
outpuStream.flush();
outpuStream.close();
// create the end of sha512
byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (IOException ex) {
logger.info("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (NoSuchAlgorithmException ex) {
logger.info("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public Data getSmall(Long id) {
try {
String mediaPath = getFileData(injectedData.id);
LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
LOGGER.info("Move done");
return injectedData;
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
}
public static void removeTemporaryFile(long idData) {
String filepath = DataResource.getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (IOException e) {
LOGGER.info("can not delete temporary file : {}", Paths.get(filepath));
e.printStackTrace();
}
}
}
// save uploaded file to a defined location on the server
static String saveFile(InputStream uploadedInputStream, String serverLocation) {
String out = "";
try {
OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[CHUNK_SIZE_IN];
MessageDigest md = MessageDigest.getInstance("SHA-512");
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
//logger.info("write {}", read);
md.update(bytes, 0, read);
outpuStream.write(bytes, 0, read);
}
LOGGER.info("Flush input stream ... {}", serverLocation);
System.out.flush();
outpuStream.flush();
outpuStream.close();
// create the end of sha512
byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (IOException ex) {
LOGGER.info("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (NoSuchAlgorithmException ex) {
LOGGER.info("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public Data getSmall(Long id) {
try {
return SqlWrapper.get(Data.class, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@POST
@Path("/upload/")
@Consumes({MediaType.MULTIPART_FORM_DATA})
@RolesAllowed("ADMIN")
public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.info("===================================================");
logger.info("== DATA uploadFile {}", (gc==null?"null":gc.userByToken));
logger.info("===================================================");
//public NodeSmall uploadFile(final FormDataMultiPart form) {
logger.info("Upload file: ");
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
saveFile(fileInputStream, filePath);
return Response.ok("Data uploaded successfully !!").build();
//return null;
}
@GET
@Path("{id}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
logger.info("== DATA retriveDataId ? id={} user={}", id, (gc==null?"null":gc.userByToken));
//logger.info("===================================================");
Data value = getSmall(id);
if (value == null) {
Response.status(404).
entity("media NOT FOUND: " + id).
type("text/plain").
build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
@GET
@Path("thumbnail/{id}")
@RolesAllowed("USER")
@PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retriveDataThumbnailId(@Context SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) String token,
@HeaderParam("Range") String range,
@PathParam("id") Long id) throws Exception {
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
//logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user));
//logger.info("===================================================");
Data value = getSmall(id);
if (value == null) {
return Response.status(404).
entity("media NOT FOUND: " + id).
type("text/plain").
build();
}
String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).
entity("{\"error\":\"media Does not exist: " + id + "\"}").
type("application/json").
build();
}
if ( value.mimeType.contentEquals("image/jpeg")
|| value.mimeType.contentEquals("image/png")
// || value.mimeType.contentEquals("image/webp")
) {
// reads input image
BufferedImage inputImage = ImageIO.read(inputFile);
int scaledWidth = 250;
int scaledHeight = (int)((float)inputImage.getHeight() / (float)inputImage.getWidth() * (float) scaledWidth);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// create the output stream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// TODO: check how to remove buffer file !!! here, it is not needed at all...
ImageIO.write( outputImage, "JPG", baos);
return null;
}
@POST
@Path("/upload/")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@RolesAllowed("ADMIN")
public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken));
LOGGER.info("===================================================");
//public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload file: ");
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
saveFile(fileInputStream, filePath);
return Response.ok("Data uploaded successfully !!").build();
//return null;
}
@GET
@Path("{id}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
LOGGER.info("== DATA retriveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
//logger.info("===================================================");
Data value = getSmall(id);
if (value == null) {
Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
@GET
@Path("thumbnail/{id}")
@RolesAllowed("USER")
@PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retriveDataThumbnailId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id)
throws Exception {
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
//logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user));
//logger.info("===================================================");
Data value = getSmall(id);
if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build();
}
if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png")
// || value.mimeType.contentEquals("image/webp")
) {
// reads input image
BufferedImage inputImage = ImageIO.read(inputFile);
int scaledWidth = 250;
int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() * (float) scaledWidth);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// create the output stream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// TODO: check how to remove buffer file !!! here, it is not needed at all...
ImageIO.write(outputImage, "JPG", baos);
} catch (IOException e) {
e.printStackTrace();
return Response.status(500).
entity("Internal Error: resize fail: " + e.getMessage()).
type("text/plain").
build();
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain").build();
}
byte[] imageData = baos.toByteArray();
//Response.ok(new ByteArrayInputStream(imageData)).build();
Response.ResponseBuilder out = Response.ok(imageData)
.header(HttpHeaders.CONTENT_LENGTH, imageData.length);
out.type("image/jpeg");
// TODO: move this in a decorator !!!
CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
cc.setNoCache(false);
out.cacheControl(cc);
return out.build();
}
return buildStream(filePathName, range, value.mimeType);
}
//@Secured
@GET
@Path("{id}/{name}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id, @PathParam("name") String name) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
logger.info("== DATA retriveDataFull ? id={} user={}", id, (gc==null?"null":gc.userByToken));
//logger.info("===================================================");
Data value = getSmall(id);
if (value == null) {
Response.status(404).
entity("media NOT FOUND: " + id).
type("text/plain").
build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
/**
* Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541
*
* @param range range header
* @return Streaming output
* @throws Exception IOException if an error occurs in streaming.
*/
private Response buildStream(final String filename, final String range, String mimeType) throws Exception {
File file = new File(filename);
//logger.info("request range : {}", range);
// range not requested : Firefox does not send range headers
if (range == null) {
final StreamingOutput output = new StreamingOutput() {
@Override
public void write(OutputStream out) {
try (FileInputStream in = new FileInputStream(file)) {
byte[] buf = new byte[1024 * 1024];
int len;
while ((len = in.read(buf)) != -1) {
try {
out.write(buf, 0, len);
out.flush();
//logger.info("---- wrote {} bytes file ----", len);
} catch (IOException ex) {
logger.info("remote close connection");
break;
}
}
} catch (IOException ex) {
throw new InternalServerErrorException(ex);
}
}
};
Response.ResponseBuilder out = Response.ok(output)
.header(HttpHeaders.CONTENT_LENGTH, file.length());
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
String[] ranges = range.split("=")[1].split("-");
final long from = Long.parseLong(ranges[0]);
//logger.info("request range : {}", ranges.length);
//Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
long to = CHUNK_SIZE + from;
if (ranges.length == 1) {
to = file.length() - 1;
} else {
if (to >= file.length()) {
to = (long) (file.length() - 1);
}
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
//logger.info("responseRange: {}", responseRange);
final RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(from);
final long len = to - from + 1;
final MediaStreamer streamer = new MediaStreamer(len, raf);
Response.ResponseBuilder out = Response.ok(streamer)
.status(Response.Status.PARTIAL_CONTENT)
.header("Accept-Ranges", "bytes")
.header("Content-Range", responseRange)
.header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth())
.header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified()));
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
byte[] imageData = baos.toByteArray();
//Response.ok(new ByteArrayInputStream(imageData)).build();
Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, imageData.length);
out.type("image/jpeg");
// TODO: move this in a decorator !!!
CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
cc.setNoCache(false);
out.cacheControl(cc);
return out.build();
}
return buildStream(filePathName, range, value.mimeType);
}
//@Secured
@GET
@Path("{id}/{name}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id,
@PathParam("name") String name) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
LOGGER.info("== DATA retriveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
//logger.info("===================================================");
Data value = getSmall(id);
if (value == null) {
Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
/**
* Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541
*
* @param range range header
* @return Streaming output
* @throws Exception IOException if an error occurs in streaming.
*/
private Response buildStream(final String filename, final String range, String mimeType) throws Exception {
File file = new File(filename);
//logger.info("request range : {}", range);
// range not requested : Firefox does not send range headers
if (range == null) {
final StreamingOutput output = new StreamingOutput() {
@Override
public void write(OutputStream out) {
try (FileInputStream in = new FileInputStream(file)) {
byte[] buf = new byte[1024 * 1024];
int len;
while ((len = in.read(buf)) != -1) {
try {
out.write(buf, 0, len);
out.flush();
//logger.info("---- wrote {} bytes file ----", len);
} catch (IOException ex) {
LOGGER.info("remote close connection");
break;
}
}
} catch (IOException ex) {
throw new InternalServerErrorException(ex);
}
}
};
Response.ResponseBuilder out = Response.ok(output).header(HttpHeaders.CONTENT_LENGTH, file.length());
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
String[] ranges = range.split("=")[1].split("-");
final long from = Long.parseLong(ranges[0]);
//logger.info("request range : {}", ranges.length);
//Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
long to = CHUNK_SIZE + from;
if (ranges.length == 1) {
to = file.length() - 1;
} else {
if (to >= file.length()) {
to = (long) (file.length() - 1);
}
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
//logger.info("responseRange: {}", responseRange);
final RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(from);
final long len = to - from + 1;
final MediaStreamer streamer = new MediaStreamer(len, raf);
Response.ResponseBuilder out = Response.ok(streamer).status(Response.Status.PARTIAL_CONTENT).header("Accept-Ranges", "bytes").header("Content-Range", responseRange)
.header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth()).header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified()));
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
public static void undelete(Long id) throws Exception {
SqlWrapper.unsetDelete(Data.class, id);
}
}

View File

@ -3,100 +3,110 @@ package org.kar.archidata.api;
import java.io.File;
import java.util.List;
import jakarta.ws.rs.*;
import org.kar.archidata.annotation.security.PermitAll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.NotSupportedException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.CacheControl;
import jakarta.ws.rs.core.PathSegment;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.ResponseBuilder;
import org.kar.archidata.annotation.security.PermitAll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FrontGeneric {
static final Logger logger = LoggerFactory.getLogger(FrontGeneric.class);
private static final Logger LOGGER = LoggerFactory.getLogger(FrontGeneric.class);
protected String baseFrontFolder = "/data/front";
private String getExtension(String filename) {
if (filename.contains(".")) {
return filename.substring(filename.lastIndexOf(".") + 1);
}
return "";
if (filename.contains(".")) {
return filename.substring(filename.lastIndexOf(".") + 1);
}
return "";
}
private Response retrive(String fileName) throws Exception {
String filePathName = baseFrontFolder + File.separator + fileName;
String extention = getExtension(filePathName);
String mineType = null;
LOGGER.debug("try retrive : '{}' '{}'", filePathName, extention);
if (extention.length() != 0 && extention.length() <= 5) {
if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) {
mineType = "image/jpeg";
} else if (extention.equalsIgnoreCase("gif")) {
mineType = "image/gif";
} else if (extention.equalsIgnoreCase("png")) {
mineType = "image/png";
} else if (extention.equalsIgnoreCase("svg")) {
mineType = "image/svg+xml";
} else if (extention.equalsIgnoreCase("webp")) {
mineType = "image/webp";
} else if (extention.equalsIgnoreCase("js")) {
mineType = "application/javascript";
} else if (extention.equalsIgnoreCase("json")) {
mineType = "application/json";
} else if (extention.equalsIgnoreCase("ico")) {
mineType = "image/x-icon";
} else if (extention.equalsIgnoreCase("html")) {
mineType = "text/html";
} else if (extention.equalsIgnoreCase("css")) {
mineType = "text/css";
} else if (extention.equalsIgnoreCase("mka")) {
mineType = "audio/x-matroska";
} else if (extention.equalsIgnoreCase("mkv")) {
mineType = "video/x-matroska";
} else if (extention.equalsIgnoreCase("webm")) {
mineType = "video/webm";
} else {
throw new NotSupportedException("Not supported model: '" + fileName + "'");
}
} else {
mineType = "text/html";
filePathName = baseFrontFolder + File.separator + "index.html";
}
LOGGER.debug(" ==> '[}'", filePathName);
// reads input image
File download = new File(filePathName);
if (!download.exists()) {
throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'");
}
ResponseBuilder response = Response.ok((Object) download);
// use this if I want to download the file:
//response.header("Content-Disposition", "attachment; filename=" + fileName);
CacheControl cc = new CacheControl();
cc.setMaxAge(60);
cc.setNoCache(false);
response.cacheControl(cc);
response.type(mineType);
return response.build();
}
@GET
@PermitAll()
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 1, unit = TimeUnit.DAYS)
public Response retrive0() throws Exception {
return retrive("index.html");
}
@GET
@Path("{any: .*}")
@PermitAll()
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retrive1(@PathParam("any") List<PathSegment> segments) throws Exception {
String filename = "";
for (PathSegment elem : segments) {
if (!filename.isEmpty()) {
filename += File.separator;
}
filename += elem.getPath();
}
return retrive(filename);
}
private Response retrive(String fileName) throws Exception {
String filePathName = baseFrontFolder + File.separator + fileName;
String extention = getExtension(filePathName);
String mineType = null;
logger.debug("try retrive : '{}' '{}'", filePathName, extention);
if (extention.length() !=0 && extention.length() <= 5) {
if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) {
mineType = "image/jpeg";
} else if (extention.equalsIgnoreCase("gif")) {
mineType = "image/gif";
} else if (extention.equalsIgnoreCase("png")) {
mineType = "image/png";
} else if (extention.equalsIgnoreCase("svg")) {
mineType = "image/svg+xml";
} else if (extention.equalsIgnoreCase("webp")) {
mineType = "image/webp";
} else if (extention.equalsIgnoreCase("js")) {
mineType = "application/javascript";
} else if (extention.equalsIgnoreCase("json")) {
mineType = "application/json";
} else if (extention.equalsIgnoreCase("ico")) {
mineType = "image/x-icon";
} else if (extention.equalsIgnoreCase("html")) {
mineType = "text/html";
} else if (extention.equalsIgnoreCase("css")) {
mineType = "text/css";
} else {
throw new NotSupportedException("Not supported model: '" + fileName + "'");
}
} else {
mineType = "text/html";
filePathName = baseFrontFolder + File.separator + "index.html";
}
logger.debug(" ==> '[}'", filePathName);
// reads input image
File download = new File(filePathName);
if (!download.exists()) {
throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'");
}
ResponseBuilder response = Response.ok((Object)download);
// use this if I want to download the file:
//response.header("Content-Disposition", "attachment; filename=" + fileName);
CacheControl cc = new CacheControl();
cc.setMaxAge(60);
cc.setNoCache(false);
response.cacheControl(cc);
response.type(mineType);
return response.build();
}
@GET
@PermitAll()
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 1, unit = TimeUnit.DAYS)
public Response retrive0() throws Exception {
return retrive("index.html");
}
@GET
@Path("{any: .*}")
@PermitAll()
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retrive1(@PathParam("any") List<PathSegment> segments) throws Exception {
String filename = "";
for (PathSegment elem: segments) {
if (!filename.isEmpty()) {
filename += File.separator;
}
filename += elem.getPath();
}
return retrive(filename);
}
}

View File

@ -1,8 +1,5 @@
package org.kar.archidata.api;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
@ -10,51 +7,55 @@ import java.io.RandomAccessFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.StreamingOutput;
public class MediaStreamer implements StreamingOutput {
static final Logger logger = LoggerFactory.getLogger(MediaStreamer.class);
private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
final byte[] buf = new byte[CHUNK_SIZE];
private long length;
private RandomAccessFile raf;
public MediaStreamer(long length, RandomAccessFile raf) throws IOException {
//logger.info("request stream of {} data", length / 1024);
if (length<0) {
throw new IOException("Wrong size of the file to stream: " + length);
}
this.length = length;
this.raf = raf;
}
@Override
public void write(OutputStream outputStream) {
try {
while (length != 0) {
int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length);
try {
outputStream.write(buf, 0, read);
} catch (IOException ex) {
logger.info("remote close connection");
break;
}
length -= read;
}
} catch (IOException ex) {
throw new InternalServerErrorException(ex);
} catch (WebApplicationException ex) {
throw new InternalServerErrorException(ex);
} finally {
try {
raf.close();
} catch (IOException ex) {
ex.printStackTrace();
throw new InternalServerErrorException(ex);
}
}
}
public long getLenth() {
return length;
}
private static final Logger LOGGER = LoggerFactory.getLogger(MediaStreamer.class);
private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
final byte[] buf = new byte[CHUNK_SIZE];
private long length;
private RandomAccessFile raf;
public MediaStreamer(long length, RandomAccessFile raf) throws IOException {
//logger.info("request stream of {} data", length / 1024);
if (length < 0) {
throw new IOException("Wrong size of the file to stream: " + length);
}
this.length = length;
this.raf = raf;
}
@Override
public void write(OutputStream outputStream) {
try {
while (length != 0) {
int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length);
try {
outputStream.write(buf, 0, read);
} catch (IOException ex) {
LOGGER.info("remote close connection");
break;
}
length -= read;
}
} catch (IOException ex) {
throw new InternalServerErrorException(ex);
} catch (WebApplicationException ex) {
throw new InternalServerErrorException(ex);
} finally {
try {
raf.close();
} catch (IOException ex) {
ex.printStackTrace();
throw new InternalServerErrorException(ex);
}
}
}
public long getLenth() {
return length;
}
}

View File

@ -1,29 +1,26 @@
package org.kar.archidata.catcher;
import jakarta.ws.rs.core.MediaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class ExceptionCatcher
implements ExceptionMapper<Exception> {
final Logger logger = LoggerFactory.getLogger(ExceptionCatcher.class);
@Override
public Response toResponse(Exception exception) {
logger.warn("Catch exception (not managed...):");
RestErrorResponse ret = build(exception);
logger.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(Exception exception) {
return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch Unknown Exception", exception.getMessage());
}
public class ExceptionCatcher implements ExceptionMapper<Exception> {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatcher.class);
@Override
public Response toResponse(Exception exception) {
LOGGER.warn("Catch exception (not managed...):");
RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(Exception exception) {
return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch Unknown Exception", exception.getMessage());
}
}

View File

@ -1,29 +1,25 @@
package org.kar.archidata.catcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.ClientErrorException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FailException404API
implements ExceptionMapper<ClientErrorException> {
final Logger logger = LoggerFactory.getLogger(FailException404API.class);
@Override
public Response toResponse(ClientErrorException exception) {
RestErrorResponse ret = build(exception);
logger.error("Error UUID={}", ret.uuid);
return Response.status(exception.getResponse().getStatusInfo().toEnum())
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(ClientErrorException exception) {
return new RestErrorResponse(exception.getResponse().getStatusInfo().toEnum(), "Catch system exception" , exception.getMessage());
}
public class FailException404API implements ExceptionMapper<ClientErrorException> {
private static final Logger LOGGER = LoggerFactory.getLogger(FailException404API.class);
@Override
public Response toResponse(ClientErrorException exception) {
RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
return Response.status(exception.getResponse().getStatusInfo().toEnum()).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(ClientErrorException exception) {
return new RestErrorResponse(exception.getResponse().getStatusInfo().toEnum(), "Catch system exception", exception.getMessage());
}
}

View File

@ -1,31 +1,27 @@
package org.kar.archidata.catcher;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import org.kar.archidata.exception.FailException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class FailExceptionCatcher
implements ExceptionMapper<FailException> {
final Logger logger = LoggerFactory.getLogger(FailExceptionCatcher.class);
@Override
public Response toResponse(FailException exception) {
RestErrorResponse ret = build(exception);
logger.error("Error UUID={}", ret.uuid);
// Not display backtrace ==> this may be a normal case ...
//exception.printStackTrace();
return Response.status(exception.status)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(FailException exception) {
return new RestErrorResponse(exception.status, "Request Fail", exception.getMessage());
}
public class FailExceptionCatcher implements ExceptionMapper<FailException> {
private static final Logger LOGGER = LoggerFactory.getLogger(FailExceptionCatcher.class);
@Override
public Response toResponse(FailException exception) {
RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
// Not display backtrace ==> this may be a normal case ...
//exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(FailException exception) {
return new RestErrorResponse(exception.status, "Request Fail", exception.getMessage());
}
}

View File

@ -1,30 +1,26 @@
package org.kar.archidata.catcher;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import org.kar.archidata.exception.InputException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class InputExceptionCatcher
implements ExceptionMapper<InputException> {
final Logger logger = LoggerFactory.getLogger(InputExceptionCatcher.class);
@Override
public Response toResponse(InputException exception) {
RestErrorResponse ret = build(exception);
logger.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(exception.status)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(InputException exception) {
return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'" , exception.getMessage());
}
public class InputExceptionCatcher implements ExceptionMapper<InputException> {
private static final Logger LOGGER = LoggerFactory.getLogger(InputExceptionCatcher.class);
@Override
public Response toResponse(InputException exception) {
RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(InputException exception) {
return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'", exception.getMessage());
}
}

View File

@ -7,7 +7,7 @@ import jakarta.ws.rs.core.Response;
public class RestErrorResponse {
public UUID uuid = UUID.randomUUID();
public String time;
public String time;
public String error;
public String message;
final public int status;
@ -20,6 +20,7 @@ public class RestErrorResponse {
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
}
public RestErrorResponse(Response.Status status, String error, String message) {
this.time = Instant.now().toString();
this.error = error;
@ -27,6 +28,7 @@ public class RestErrorResponse {
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
}
public RestErrorResponse(Response.Status status) {
this.time = Instant.now().toString();
this.status = status.getStatusCode();

View File

@ -1,30 +1,26 @@
package org.kar.archidata.catcher;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import org.kar.archidata.exception.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class SystemExceptionCatcher
implements ExceptionMapper<SystemException> {
final Logger logger = LoggerFactory.getLogger(SystemExceptionCatcher.class);
@Override
public Response toResponse(SystemException exception) {
RestErrorResponse ret = build(exception);
logger.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(exception.status)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(SystemException exception) {
return new RestErrorResponse(exception.status, "System error", exception.getMessage());
}
public class SystemExceptionCatcher implements ExceptionMapper<SystemException> {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemExceptionCatcher.class);
@Override
public Response toResponse(SystemException exception) {
RestErrorResponse ret = build(exception);
LOGGER.error("Error UUID={}", ret.uuid);
exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(SystemException exception) {
return new RestErrorResponse(exception.status, "System error", exception.getMessage());
}
}

View File

@ -6,87 +6,82 @@ import org.slf4j.LoggerFactory;
public class DBConfig {
static final Logger LOGGER = LoggerFactory.getLogger(SqlWrapper.class);
private final String type;
private final String hostname;
private final int port;
private final String login;
private final String password;
private final String dbName;
private final boolean keepConnected;
public DBConfig(String type, String hostname, Integer port, String login, String password, String dbName, boolean keepConnected) {
if (type == null) {
this.type = "mysql";
} else {
this.type = type;
}
if (hostname == null) {
this.hostname = "localhost";
} else {
this.hostname = hostname;
}
if (port == null) {
this.port = 3306;
} else {
this.port = port;
}
this.login = login;
this.password = password;
this.dbName = dbName;
this.keepConnected = keepConnected;
}
@Override
public String toString() {
return "DBConfig{" +
"type='" + type + '\'' +
", hostname='" + hostname + '\'' +
", port=" + port +
", login='" + login + '\'' +
", password='" + password + '\'' +
", dbName='" + dbName + '\'' +
'}';
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
public String getDbName() {
return dbName;
}
public boolean getKeepConnected() {
return keepConnected;
}
public String getUrl() {
return getUrl(false);
}
public String getUrl(boolean isRoot) {
if (type.equals("sqlite")) {
if (isRoot == true) {
LOGGER.error("Can not manage root connection on SQLite...");
}
if (this.hostname.equals("memory")) {
return "jdbc:sqlite::memory:";
}
return "jdbc:sqlite:" + this.hostname + ".db";
}
if (isRoot) {
return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC";
}
private final String type;
private final String hostname;
private final int port;
private final String login;
private final String password;
private final String dbName;
private final boolean keepConnected;
public DBConfig(String type, String hostname, Integer port, String login, String password, String dbName, boolean keepConnected) {
if (type == null) {
this.type = "mysql";
} else {
this.type = type;
}
if (hostname == null) {
this.hostname = "localhost";
} else {
this.hostname = hostname;
}
if (port == null) {
this.port = 3306;
} else {
this.port = port;
}
this.login = login;
this.password = password;
this.dbName = dbName;
this.keepConnected = keepConnected;
}
@Override
public String toString() {
return "DBConfig{type='" + type + '\'' + ", hostname='" + hostname + '\'' + ", port=" + port + ", login='" + login + '\'' + ", password='" + password + '\'' + ", dbName='" + dbName + "' }";
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
public String getDbName() {
return dbName;
}
public boolean getKeepConnected() {
return keepConnected;
}
public String getUrl() {
return getUrl(false);
}
public String getUrl(boolean isRoot) {
if (type.equals("sqlite")) {
if (isRoot == true) {
LOGGER.error("Can not manage root connection on SQLite...");
}
if (this.hostname.equals("memory")) {
return "jdbc:sqlite::memory:";
}
return "jdbc:sqlite:" + this.hostname + ".db";
}
if (isRoot) {
return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC";
}
return "jdbc:" + this.type + "://" + this.hostname + ":" + this.port + "/" + this.dbName + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC";
}
}
}

View File

@ -2,7 +2,9 @@ package org.kar.archidata.db;
import java.io.Closeable;
import java.io.IOException;
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@ -11,69 +13,70 @@ import org.slf4j.LoggerFactory;
public class DBEntry implements Closeable {
final static Logger LOGGER = LoggerFactory.getLogger(DBEntry.class);
public DBConfig config;
public Connection connection;
private static List<DBEntry> stored = new ArrayList<>();
private DBEntry(DBConfig config, boolean root) throws IOException {
this.config = config;
if (root) {
connectRoot();
} else {
connect();
}
}
public static DBEntry createInterface(DBConfig config) throws IOException {
return createInterface(config, false);
}
public static DBEntry createInterface(DBConfig config, boolean root) throws IOException {
if (config.getKeepConnected()) {
for (DBEntry elem : stored) {
if (elem == null) {
continue;
}
if (elem.config.getUrl().equals(config.getUrl())) {
return elem;
}
}
DBEntry tmp = new DBEntry(config, root);
stored.add(tmp);
return tmp;
} else {
return new DBEntry(config, root);
}
}
public void connectRoot() throws IOException {
try {
connection = DriverManager.getConnection(config.getUrl(true), config.getLogin(), config.getPassword());
} catch (SQLException ex) {
throw new IOException("Connection db fail: " + ex.getMessage());
}
}
public void connect() throws IOException {
try {
connection = DriverManager.getConnection(config.getUrl(), config.getLogin(), config.getPassword());
} catch (SQLException ex) {
throw new IOException("Connection db fail: " + ex.getMessage());
}
}
public DBConfig config;
public Connection connection;
private static List<DBEntry> stored = new ArrayList<>();
private DBEntry(DBConfig config, boolean root) throws IOException {
this.config = config;
if (root) {
connectRoot();
} else {
connect();
}
}
public static DBEntry createInterface(DBConfig config) throws IOException {
return createInterface(config, false);
}
public static DBEntry createInterface(DBConfig config, boolean root) throws IOException {
if (config.getKeepConnected()) {
for (DBEntry elem : stored) {
if (elem == null) {
continue;
}
if (elem.config.getUrl().equals(config.getUrl())) {
return elem;
}
}
DBEntry tmp = new DBEntry(config, root);
stored.add(tmp);
return tmp;
} else {
return new DBEntry(config, root);
}
}
public void connectRoot() throws IOException {
try {
connection = DriverManager.getConnection(config.getUrl(true), config.getLogin(), config.getPassword());
} catch (SQLException ex) {
throw new IOException("Connection db fail: " + ex.getMessage());
}
}
public void connect() throws IOException {
try {
connection = DriverManager.getConnection(config.getUrl(), config.getLogin(), config.getPassword());
} catch (SQLException ex) {
throw new IOException("Connection db fail: " + ex.getMessage());
}
}
@Override
public void close() throws IOException {
if (config.getKeepConnected()) {
return;
}
try {
//connection.commit();
connection.close();
} catch (SQLException ex) {
throw new IOException("Dis-connection db fail: " + ex.getMessage());
}
try {
//connection.commit();
connection.close();
} catch (SQLException ex) {
throw new IOException("Dis-connection db fail: " + ex.getMessage());
}
}
}

View File

@ -5,10 +5,12 @@ import jakarta.ws.rs.core.Response;
public class FailException extends Exception {
private static final long serialVersionUID = 1L;
public final Response.Status status;
public FailException(Response.Status status, String message) {
super(message);
this.status = status;
}
public FailException(String message) {
super(message);
this.status = Response.Status.BAD_REQUEST;

View File

@ -6,11 +6,13 @@ public class InputException extends Exception {
private static final long serialVersionUID = 1L;
public final String missingVariable;
public final Response.Status status;
public InputException(Response.Status status, String variable, String message) {
super(message);
this.missingVariable = variable;
this.status = status;
}
public InputException(String variable, String message) {
super(message);
this.missingVariable = variable;

View File

@ -4,6 +4,7 @@ import jakarta.ws.rs.core.Response;
public class NotFoundException extends FailException {
private static final long serialVersionUID = 1L;
public NotFoundException(String message) {
super(Response.Status.NOT_FOUND, message);
}

View File

@ -4,12 +4,12 @@ import java.util.UUID;
public class RESTErrorResponseExeption extends Exception {
public UUID uuid;
public String time;
public String time;
public String error;
public String message;
public int status;
public String statusMessage;
public RESTErrorResponseExeption() {
super();
this.uuid = null;
@ -19,8 +19,8 @@ public class RESTErrorResponseExeption extends Exception {
this.status = 0;
this.statusMessage = null;
}
public RESTErrorResponseExeption(UUID uuid, String time, String error, String message, int status,
String statusMessage) {
public RESTErrorResponseExeption(UUID uuid, String time, String error, String message, int status, String statusMessage) {
super();
this.uuid = uuid;
this.time = time;
@ -29,13 +29,10 @@ public class RESTErrorResponseExeption extends Exception {
this.status = status;
this.statusMessage = statusMessage;
}
@Override
public String toString() {
return "RESTErrorResponseExeption [uuid=" + uuid + ", time=" + time + ", error=" + error + ", message="
+ message + ", status=" + status + ", statusMessage=" + statusMessage + "]";
return "RESTErrorResponseExeption [uuid=" + uuid + ", time=" + time + ", error=" + error + ", message=" + message + ", status=" + status + ", statusMessage=" + statusMessage + "]";
}
}

View File

@ -5,10 +5,12 @@ import jakarta.ws.rs.core.Response;
public class SystemException extends Exception {
private static final long serialVersionUID = 1L;
public final Response.Status status;
public SystemException(Response.Status status, String message) {
super(message);
this.status = status;
}
public SystemException(String message) {
super(message);
this.status = Response.Status.INTERNAL_SERVER_ERROR;

View File

@ -4,6 +4,7 @@ import jakarta.ws.rs.core.Response;
public class UnAuthorizedException extends FailException {
private static final long serialVersionUID = 1L;
public UnAuthorizedException(String message) {
super(Response.Status.UNAUTHORIZED, message);
}

View File

@ -1,10 +1,26 @@
package org.kar.archidata.filter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey/45814178#45814178
// https://stackoverflow.com/questions/32817210/how-to-access-jersey-resource-secured-by-rolesallowed
import org.kar.archidata.annotation.security.DenyAll;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.catcher.RestErrorResponse;
import org.kar.archidata.model.UserByToken;
import org.kar.archidata.util.JWTWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.jwt.JWTClaimsSet;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
@ -18,23 +34,6 @@ import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.model.UserByToken;
import org.kar.archidata.util.JWTWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.jwt.JWTClaimsSet;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey/45814178#45814178
// https://stackoverflow.com/questions/32817210/how-to-access-jersey-resource-secured-by-rolesallowed
//@PreMatching
@Provider
@Priority(Priorities.AUTHENTICATION)
@ -43,189 +42,183 @@ public class AuthenticationFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
protected final String applicationName;
private static final String AUTHENTICATION_SCHEME = "Yota";
private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota";
public AuthenticationFilter(String applicationName) {
private static final String AUTHENTICATION_SCHEME = "Yota";
private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota";
public AuthenticationFilter(String applicationName) {
super();
this.applicationName = applicationName;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
/*
logger.debug("-----------------------------------------------------");
logger.debug("---- Check if have authorization ----");
logger.debug("-----------------------------------------------------");
logger.debug(" for:{}", requestContext.getUriInfo().getPath());
*/
Method method = resourceInfo.getResourceMethod();
// Access denied for all
if(method.isAnnotationPresent(DenyAll.class)) {
logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build());
return;
}
//Access allowed for all
if( method.isAnnotationPresent(PermitAll.class)) {
//logger.debug(" ==> permit all " + requestContext.getUriInfo().getPath());
// no control ...
return;
}
// this is a security guard, all the API must define their access level:
if(!method.isAnnotationPresent(RolesAllowed.class)) {
logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build());
return;
}
// Get the Authorization header from the request
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
//logger.debug("authorizationHeader: {}", authorizationHeader);
if(authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) {
MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
for (Entry<String, List<String>> item: quaryparam.entrySet()) {
if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) {
if (!item.getValue().isEmpty()) {
authorizationHeader = item.getValue().get(0);
}
break;
}
}
}
// logger.debug("authorizationHeader: {}", authorizationHeader);
boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)"
if (!isApplicationToken && !isJwtToken) {
logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath());
return;
}
UserByToken userByToken = null;
if (isJwtToken) {
// Extract the token from the Authorization header (Remove "Yota ")
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
//logger.debug("token: {}", token);
try {
userByToken = validateJwtToken(token);
} catch (Exception e) {
logger.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
logger.warn("get a NULL user ...");
abortWithUnauthorized(requestContext, "get a NULL user ...");
return;
}
} else {
// Extract the token from the Authorization header (Remove "Zota ")
String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
//logger.debug("token: {}", token);
try {
userByToken = validateToken(token);
} catch (Exception e) {
logger.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: "+ e.getMessage());
return;
}
if (userByToken == null) {
logger.warn("get a NULL application ...");
abortWithUnauthorized(requestContext, "get a NULL application ...");
return;
}
}
// create the security context model:
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
// retrieve the allowed right:
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
List<String> roles = Arrays.asList(rolesAnnotation.value());
// check if the user have the right:
boolean haveRight = false;
for (String role : roles) {
if (userContext.isUserInRole(role)) {
haveRight = true;
break;
}
}
//Is user valid?
if( ! haveRight) {
logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build());
return;
}
requestContext.setSecurityContext(userContext);
// logger.debug("Get local user : {} / {}", user, userByToken);
}
private boolean isTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " ");
}
private boolean isApplicationTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " ");
}
private void abortWithUnauthorized(ContainerRequestContext requestContext, String message) {
// Abort the filter chain with a 401 status code response
// The WWW-Authenticate header is sent along with the response
logger.warn("abortWithUnauthorized:");
public void filter(ContainerRequestContext requestContext) throws IOException {
/*
logger.debug("-----------------------------------------------------");
logger.debug("---- Check if have authorization ----");
logger.debug("-----------------------------------------------------");
logger.debug(" for:{}", requestContext.getUriInfo().getPath());
*/
Method method = resourceInfo.getResourceMethod();
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build());
return;
}
//Access allowed for all
if (method.isAnnotationPresent(PermitAll.class)) {
//logger.debug(" ==> permit all " + requestContext.getUriInfo().getPath());
// no control ...
return;
}
// this is a security guard, all the API must define their access level:
if (!method.isAnnotationPresent(RolesAllowed.class)) {
logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build());
return;
}
// Get the Authorization header from the request
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
//logger.debug("authorizationHeader: {}", authorizationHeader);
if (authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) {
MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
for (Entry<String, List<String>> item : quaryparam.entrySet()) {
if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) {
if (!item.getValue().isEmpty()) {
authorizationHeader = item.getValue().get(0);
}
break;
}
}
}
// logger.debug("authorizationHeader: {}", authorizationHeader);
boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)"
if (!isApplicationToken && !isJwtToken) {
logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath());
return;
}
UserByToken userByToken = null;
if (isJwtToken) {
// Extract the token from the Authorization header (Remove "Yota ")
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
//logger.debug("token: {}", token);
try {
userByToken = validateJwtToken(token);
} catch (Exception e) {
logger.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
logger.warn("get a NULL user ...");
abortWithUnauthorized(requestContext, "get a NULL user ...");
return;
}
} else {
// Extract the token from the Authorization header (Remove "Zota ")
String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
//logger.debug("token: {}", token);
try {
userByToken = validateToken(token);
} catch (Exception e) {
logger.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
logger.warn("get a NULL application ...");
abortWithUnauthorized(requestContext, "get a NULL application ...");
return;
}
}
// create the security context model:
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
// retrieve the allowed right:
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
List<String> roles = Arrays.asList(rolesAnnotation.value());
// check if the user have the right:
boolean haveRight = false;
for (String role : roles) {
if (userContext.isUserInRole(role)) {
haveRight = true;
break;
}
}
//Is user valid?
if (!haveRight) {
logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build());
return;
}
requestContext.setSecurityContext(userContext);
// logger.debug("Get local user : {} / {}", user, userByToken);
}
private boolean isTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " ");
}
private boolean isApplicationTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " ");
}
private void abortWithUnauthorized(ContainerRequestContext requestContext, String message) {
// Abort the filter chain with a 401 status code response
// The WWW-Authenticate header is sent along with the response
logger.warn("abortWithUnauthorized:");
RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
logger.error("Error UUID={}", ret.uuid);
requestContext.abortWith(Response.status(ret.status)
.header(HttpHeaders.WWW_AUTHENTICATE,
AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)")
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build());
}
protected UserByToken validateToken(String authorization) throws Exception {
logger.info("Must be Override by the application implmentation, otherwise it dose not work");
return null;
}
// must be override to be good implementation
protected UserByToken validateJwtToken(String authorization) throws Exception {
//logger.debug(" validate token : " + authorization);
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
if (ret == null) {
logger.error("The token is not valid: '{}'", authorization);
return null;
}
// check userID
String userUID = ret.getSubject();
long id = Long.parseLong(userUID);
UserByToken user = new UserByToken();
user.id = id;
user.name = (String)ret.getClaim("login");
user.type = UserByToken.TYPE_USER;
Object rowRight = ret.getClaim("right");
if (rowRight != null) {
Map<String, Map<String,Object>> rights = (Map<String, Map<String,Object>>) ret.getClaim("right");
if (rights.containsKey(this.applicationName)) {
user.right = rights.get(this.applicationName);
} else {
logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
}
}
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight);
return user;
//return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") );
}
requestContext.abortWith(Response.status(ret.status).header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)").entity(ret)
.type(MediaType.APPLICATION_JSON).build());
}
protected UserByToken validateToken(String authorization) throws Exception {
logger.info("Must be Override by the application implmentation, otherwise it dose not work");
return null;
}
// must be override to be good implementation
protected UserByToken validateJwtToken(String authorization) throws Exception {
//logger.debug(" validate token : " + authorization);
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
if (ret == null) {
logger.error("The token is not valid: '{}'", authorization);
return null;
}
// check userID
String userUID = ret.getSubject();
long id = Long.parseLong(userUID);
UserByToken user = new UserByToken();
user.id = id;
user.name = (String) ret.getClaim("login");
user.type = UserByToken.TYPE_USER;
Object rowRight = ret.getClaim("right");
if (rowRight != null) {
Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
if (rights.containsKey(this.applicationName)) {
user.right = rights.get(this.applicationName);
} else {
logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
}
}
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight);
return user;
//return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") );
}
}

View File

@ -1,25 +1,23 @@
package org.kar.archidata.filter;
import java.io.IOException;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
public class CORSFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
//System.err.println("filter cors ..." + request.toString());
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers", "*");
// "Origin, content-type, Content-type, Accept, authorization, mime-type, filename");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
//System.err.println("filter cors ..." + request.toString());
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers", "*");
// "Origin, content-type, Content-type, Accept, authorization, mime-type, filename");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}

View File

@ -1,22 +1,22 @@
package org.kar.archidata.filter;
import org.kar.archidata.model.UserByToken;
import java.security.Principal;
import org.kar.archidata.model.UserByToken;
public class GenericContext implements Principal {
public UserByToken userByToken;
public GenericContext(UserByToken userByToken) {
this.userByToken = userByToken;
}
@Override
public String getName() {
if (this.userByToken == null) {
return "???";
}
return this.userByToken.name;
}
public UserByToken userByToken;
public GenericContext(UserByToken userByToken) {
this.userByToken = userByToken;
}
@Override
public String getName() {
if (this.userByToken == null) {
return "???";
}
return this.userByToken.name;
}
}

View File

@ -1,48 +1,49 @@
package org.kar.archidata.filter;
import java.security.Principal;
import org.kar.archidata.model.UserByToken;
import jakarta.ws.rs.core.SecurityContext;
import java.security.Principal;
// https://simplapi.wordpress.com/2015/09/19/jersey-jax-rs-securitycontext-in-action/
class MySecurityContext implements SecurityContext {
private final GenericContext contextPrincipale;
private final String sheme;
public MySecurityContext(UserByToken userByToken, String sheme) {
this.contextPrincipale = new GenericContext(userByToken);
this.sheme = sheme;
}
@Override
public Principal getUserPrincipal() {
return contextPrincipale;
}
@Override
public boolean isUserInRole(String role) {
if (contextPrincipale.userByToken != null) {
Object value = this.contextPrincipale.userByToken.right.get(role);
if (value instanceof Boolean ret) {
return ret;
}
}
return false;
}
@Override
public boolean isSecure() {
return sheme.equalsIgnoreCase("https");
}
@Override
public String getAuthenticationScheme() {
if (contextPrincipale.userByToken != null) {
return "Zota";
}
return null;
}
private final GenericContext contextPrincipale;
private final String sheme;
public MySecurityContext(UserByToken userByToken, String sheme) {
this.contextPrincipale = new GenericContext(userByToken);
this.sheme = sheme;
}
@Override
public Principal getUserPrincipal() {
return contextPrincipale;
}
@Override
public boolean isUserInRole(String role) {
if (contextPrincipale.userByToken != null) {
Object value = this.contextPrincipale.userByToken.right.get(role);
if (value instanceof Boolean ret) {
return ret;
}
}
return false;
}
@Override
public boolean isSecure() {
return sheme.equalsIgnoreCase("https");
}
@Override
public String getAuthenticationScheme() {
if (contextPrincipale.userByToken != null) {
return "Zota";
}
return null;
}
}

View File

@ -1,21 +1,20 @@
package org.kar.archidata.filter;
import java.io.IOException;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
@PreMatching
public class OptionFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (requestContext.getMethod().contentEquals("OPTIONS")) {
requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build());
}
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (requestContext.getMethod().contentEquals("OPTIONS")) {
requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build());
}
}
}

View File

@ -25,15 +25,17 @@ public class MigrationEngine {
public MigrationEngine() {
this(new ArrayList<MigrationInterface>(), null);
}
/**
* Migration engine constructor (specific mode).
* @param datas All the migration ordered.
* @param init Initialization migration model.
*/
public MigrationEngine( List<MigrationInterface> datas, MigrationInterface init) {
public MigrationEngine(List<MigrationInterface> datas, MigrationInterface init) {
this.datas = datas;
this.init = init;
}
/**
* Add a Migration in the list
* @param migration Migration to add.
@ -41,6 +43,7 @@ public class MigrationEngine {
public void add(MigrationInterface migration) {
this.datas.add(migration);
}
/**
* Set first initialization class
* @param migration migration class for first init.
@ -48,6 +51,7 @@ public class MigrationEngine {
public void setInit(MigrationInterface migration) {
init = migration;
}
/**
* Get the current version/migration name
* @return Model represent the last migration. If null then no migration has been done.
@ -59,7 +63,7 @@ public class MigrationEngine {
try {
List<MigrationModel> data = SqlWrapper.gets(MigrationModel.class, false);
if (data == null) {
LOGGER.error("Can not collect the migration table in the DB:{}" );
LOGGER.error("Can not collect the migration table in the DB:{}");
return null;
}
if (data.size() == 0) {
@ -68,15 +72,16 @@ public class MigrationEngine {
}
LOGGER.debug("List of migrations:");
for (MigrationModel elem : data) {
LOGGER.debug(" - date={} name={} end={}", elem.modify_date, elem.name, elem.terminated);
LOGGER.debug(" - date={} name={} end={}", elem.modify_date, elem.name, elem.terminated);
}
return data.get(data.size()-1);
return data.get(data.size() - 1);
} catch (Exception ex) {
LOGGER.error("Fail to Request migration table in the DB:{}", ex.getMessage());
ex.printStackTrace();
}
return null;
}
/**
* Process the automatic migration of the system
* @param config SQL connection for the migration
@ -85,11 +90,11 @@ public class MigrationEngine {
*/
public void migrate(DBConfig config) throws InterruptedException, IOException {
LOGGER.info("Execute migration ... [BEGIN]");
// STEP 1: Check the DB exist:
LOGGER.info("Verify existance of '{}'", config.getDbName());
boolean exist = SqlWrapper.isDBExist(config.getDbName());
if(!exist) {
if (!exist) {
LOGGER.warn("DB: '{}' DOES NOT EXIST ==> create one", config.getDbName());
// create the local DB:
SqlWrapper.createDB(config.getDbName());
@ -114,7 +119,7 @@ public class MigrationEngine {
ex.printStackTrace();
while (true) {
LOGGER.error("Fail to create the local DB SQL model for migaration ==> wait administrator interventions");
Thread.sleep(60*60*1000);
Thread.sleep(60 * 60 * 1000);
}
}
LOGGER.info("Create Table with : {}", sqlQuery.get(0));
@ -124,7 +129,7 @@ public class MigrationEngine {
ex.printStackTrace();
while (true) {
LOGGER.error("Fail to create the local DB model for migaration ==> wait administrator interventions");
Thread.sleep(60*60*1000);
Thread.sleep(60 * 60 * 1000);
}
}
}
@ -142,15 +147,15 @@ public class MigrationEngine {
// nothing to do the initialization model is alone and it is the first time
} else {
// we insert a placeholder to simulate all migration is well done.
String placeholderName = this.datas.get(this.datas.size()-1).getName();
String placeholderName = this.datas.get(this.datas.size() - 1).getName();
MigrationModel migrationResult = new MigrationModel();
migrationResult.name = placeholderName;
migrationResult.name = placeholderName;
migrationResult.stepId = 0;
migrationResult.terminated = true;
migrationResult.count = 0;
migrationResult.log = "Place-holder for first initialization";
try {
migrationResult = SqlWrapper.insert(migrationResult);
migrationResult.count = 0;
migrationResult.log = "Place-holder for first initialization";
try {
migrationResult = SqlWrapper.insert(migrationResult);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
@ -158,9 +163,9 @@ public class MigrationEngine {
}
} else {
if (currentVersion.terminated == false) {
while(true) {
LOGGER.error("An error occured in the last migration: '{}' defect @{}/{} ==> wait administrator interventions", currentVersion.name , currentVersion.stepId, currentVersion.count);
Thread.sleep(60*60*1000);
while (true) {
LOGGER.error("An error occured in the last migration: '{}' defect @{}/{} ==> wait administrator interventions", currentVersion.name, currentVersion.stepId, currentVersion.count);
Thread.sleep(60 * 60 * 1000);
}
}
LOGGER.info("Upgrade the system Current version: {}", currentVersion.name);
@ -168,8 +173,8 @@ public class MigrationEngine {
if (currentVersion.name.equals(this.init.getName())) {
toApply = this.datas;
} else {
for (int iii=0; iii<this.datas.size(); iii++) {
if ( ! find) {
for (int iii = 0; iii < this.datas.size(); iii++) {
if (!find) {
if (this.datas.get(iii).getName() == currentVersion.name) {
find = true;
}
@ -187,18 +192,19 @@ public class MigrationEngine {
}
LOGGER.info("Execute migration ... [ END ]");
}
public void migrateSingle(DBEntry entry, MigrationInterface elem, int id, int count) {
LOGGER.info("Migrate: [{}/{}] {} [BEGIN]", id, count, elem.getName());
StringBuilder log = new StringBuilder();
log.append("Start migration");
MigrationModel migrationResult = new MigrationModel();
migrationResult.name = elem.getName();
migrationResult.name = elem.getName();
migrationResult.stepId = 0;
migrationResult.terminated = false;
migrationResult.count = elem.getNumberOfStep();
migrationResult.log = log.toString();
try {
migrationResult = SqlWrapper.insert(migrationResult);
migrationResult.count = elem.getNumberOfStep();
migrationResult.log = log.toString();
try {
migrationResult = SqlWrapper.insert(migrationResult);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
@ -206,23 +212,24 @@ public class MigrationEngine {
if (elem.applyMigration(entry, log, migrationResult)) {
migrationResult.terminated = true;
try {
SqlWrapper.update(migrationResult, migrationResult.id, List.of("terminated"));
try {
SqlWrapper.update(migrationResult, migrationResult.id, List.of("terminated"));
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
log.append("Fail in the migration engine...");
migrationResult.log = log.toString();
SqlWrapper.update(migrationResult, migrationResult.id, List.of("log"));
try {
log.append("Fail in the migration engine...");
migrationResult.log = log.toString();
SqlWrapper.update(migrationResult, migrationResult.id, List.of("log"));
} catch (Exception e) {
e.printStackTrace();
}
while(true) {
LOGGER.error("An error occured in the migration (OUTSIDE detection): '{}' defect @{}/{} ==> wait administrator interventions", migrationResult.name , migrationResult.stepId, migrationResult.count);
while (true) {
LOGGER.error("An error occured in the migration (OUTSIDE detection): '{}' defect @{}/{} ==> wait administrator interventions", migrationResult.name, migrationResult.stepId,
migrationResult.count);
try {
Thread.sleep(60*60*1000);
Thread.sleep(60 * 60 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@ -231,13 +238,13 @@ public class MigrationEngine {
}
LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName());
}
public void revertTo(DBEntry entry, String migrationName) {
MigrationModel currentVersion = getCurrentVersion();
List<MigrationInterface> toApply = new ArrayList<>();
boolean find = false;
for (int iii=this.datas.size()-1; iii>=0; iii--) {
if ( ! find) {
for (int iii = this.datas.size() - 1; iii >= 0; iii--) {
if (!find) {
if (this.datas.get(iii).getName() == currentVersion.name) {
find = true;
}
@ -254,6 +261,7 @@ public class MigrationEngine {
revertSingle(entry, elem, id, count);
}
}
public void revertSingle(DBEntry entry, MigrationInterface elem, int id, int count) {
LOGGER.info("Revert migration: {} [BEGIN]", elem.getName());

View File

@ -1,7 +1,7 @@
package org.kar.archidata.migration;
public class MigrationException extends Exception {
private static final long serialVersionUID = 20230502L;
}

View File

@ -8,6 +8,7 @@ public interface MigrationInterface {
* @return Migration name
*/
String getName();
/**
* Migrate the system to a new version.
* @param entry DB interface for the migration.
@ -16,6 +17,7 @@ public interface MigrationInterface {
* @return true if migration is finished.
*/
boolean applyMigration(DBEntry entry, StringBuilder log, MigrationModel model);
/**
* Remove a migration the system to the previous version.
* @param entry DB interface for the migration.

View File

@ -3,31 +3,31 @@ package org.kar.archidata.migration;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericTable;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
// For logs only
//public static final String TABLE_NAME = "KAR_migration";
@SQLTableName ("KAR_migration")
@Table(name = "KAR_migration")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MigrationModel extends GenericTable{
public class MigrationModel extends GenericTable {
@SQLComment("Name of the migration")
@SQLLimitSize(256)
public String name;
@SQLNotNull
@Column(length = 256)
public String name;
@Column(nullable = false)
@SQLDefault("'0'")
@SQLComment("if the migration is well terminated or not")
public Boolean terminated = false;
@SQLComment("index in the migration progression")
public Integer stepId = 0;
@SQLComment("number of element in the migration")
public Integer count;
@SQLComment("Log generate by the migration")
public String log = "";
@SQLComment("if the migration is well terminated or not")
public Boolean terminated = false;
@SQLComment("index in the migration progression")
public Integer stepId = 0;
@SQLComment("number of element in the migration")
public Integer count;
@SQLComment("Log generate by the migration")
public String log = "";
}

View File

@ -12,19 +12,26 @@ import org.slf4j.LoggerFactory;
public class MigrationSqlStep implements MigrationInterface {
final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class);
private List<String> actions = new ArrayList<>();
private final List<String> actions = new ArrayList<>();
@Override
public String getName() {
return getClass().getCanonicalName();
}
public void display() {
for (int iii = 0; iii < this.actions.size(); iii++) {
final String action = this.actions.get(iii);
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> \n{}", iii, this.actions.size(), action);
}
}
@Override
public boolean applyMigration(DBEntry entry, StringBuilder log, MigrationModel model) {
for (int iii=0; iii<actions.size(); iii++) {
log.append("action [" + iii + "/" + actions.size() + "]\n");
LOGGER.info(" >>>> SQL ACTION : {}/{}", iii, actions.size());
String action = actions.get(iii);
public boolean applyMigration(final DBEntry entry, final StringBuilder log, final MigrationModel model) {
for (int iii = 0; iii < this.actions.size(); iii++) {
log.append("action [" + iii + "/" + this.actions.size() + "]\n");
LOGGER.info(" >>>> SQL ACTION : {}/{}", iii, this.actions.size());
final String action = this.actions.get(iii);
LOGGER.info("SQL request: ```{}```", action);
log.append("SQL: " + action + "\n");
try {
@ -33,28 +40,28 @@ public class MigrationSqlStep implements MigrationInterface {
ex.printStackTrace();
LOGGER.info("SQL request ERROR: ", ex.getMessage());
log.append("SQL request ERROR: " + ex.getMessage() + "\n");
model.stepId = iii+1;
model.stepId = iii + 1;
model.log = log.toString();
try {
SqlWrapper.update(model, model.id, List.of("stepId", "log"));
} catch (Exception e) {
try {
SqlWrapper.update(model, model.id, List.of("stepId", "log"));
} catch (final Exception e) {
e.printStackTrace();
}
return false;
}
log.append("action [" + iii + "/" + actions.size() + "] ==> DONE\n");
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> DONE", iii, actions.size());
model.stepId = iii+1;
log.append("action [" + iii + "/" + this.actions.size() + "] ==> DONE\n");
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> DONE", iii, this.actions.size());
model.stepId = iii + 1;
model.log = log.toString();
try {
SqlWrapper.update(model, model.id, List.of("stepId", "log"));
} catch (Exception e) {
try {
SqlWrapper.update(model, model.id, List.of("stepId", "log"));
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
@ -63,21 +70,22 @@ public class MigrationSqlStep implements MigrationInterface {
}
@Override
public boolean revertMigration(DBEntry entry, StringBuilder log) {
public boolean revertMigration(final DBEntry entry, final StringBuilder log) {
return false;
}
public void addAction(String action) {
actions.add(action);
public void addAction(final String action) {
this.actions.add(action);
}
public void addClass(Class<?> clazz) throws Exception {
List<String> tmp = SqlWrapper.createTable(clazz, false);
actions.addAll(tmp);
public void addClass(final Class<?> clazz) throws Exception {
final List<String> tmp = SqlWrapper.createTable(clazz, false);
this.actions.addAll(tmp);
}
@Override
public int getNumberOfStep() {
return actions.size();
return this.actions.size();
}
}

View File

@ -1,28 +1,25 @@
package org.kar.archidata.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("data")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "data")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Data extends GenericTable {
@SQLNotNull
@SQLLimitSize(128)
@SQLComment("Sha512 of the data")
public String sha512;
@SQLNotNull
@SQLLimitSize(128)
@SQLComment("Mime -type of the media")
public String mimeType;
@SQLNotNull
@SQLComment("Size in Byte of the data")
public Long size;
@Column(length = 128, nullable = false)
@SQLComment("Sha512 of the data")
public String sha512;
@Column(length = 128, nullable = false)
@SQLComment("Mime -type of the media")
public String mimeType;
@Column(nullable = false)
@SQLComment("Size in Byte of the data")
public Long size;
}

View File

@ -2,38 +2,40 @@ package org.kar.archidata.model;
import java.sql.Timestamp;
import org.kar.archidata.annotation.SQLAutoIncrement;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLCreateTime;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLDeleted;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLNotRead;
import org.kar.archidata.annotation.SQLPrimaryKey;
import org.kar.archidata.annotation.SQLUpdateTime;
import org.kar.archidata.annotation.UpdateTimestamp;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
public class GenericTable {
@SQLAutoIncrement // Add AUTO_INCREMENT modifier
@SQLPrimaryKey // Create a PRIMARY KEY based on this field
@SQLNotNull
@SQLComment("Primary key of the base")
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
@SQLComment("Primary key of the base")
public Long id = null;
@SQLNotRead
@SQLNotNull
@SQLDefault("'0'")
@SQLDeleted
@SQLComment("When delete, they are not removed, they are just set in a deleted state")
@SQLNotRead
@Column(nullable = false)
@SQLDefault("'0'")
@SQLDeleted
@SQLComment("When delete, they are not removed, they are just set in a deleted state")
public Boolean deleted = null;
@SQLNotRead
@SQLCreateTime
@SQLNotNull
@SQLComment("Create time of the object")
@SQLDefault("CURRENT_TIMESTAMP(3)")
@SQLNotRead
@CreationTimestamp
@Column(nullable = false)
@SQLComment("Create time of the object")
@SQLDefault("CURRENT_TIMESTAMP(3)")
public Timestamp create_date = null;
@SQLNotRead
@SQLUpdateTime
@SQLNotNull
@SQLComment("When update the object")
@SQLDefault("CURRENT_TIMESTAMP(3)")
@SQLNotRead
@UpdateTimestamp
@Column(nullable = false)
@SQLComment("When update the object")
@SQLDefault("CURRENT_TIMESTAMP(3)")
public Timestamp modify_date = null;
}

View File

@ -3,21 +3,22 @@ package org.kar.archidata.model;
import java.sql.Timestamp;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("applicationToken")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "applicationToken")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GenericToken extends GenericTable {
@SQLNotNull
public Long parentId;
@SQLNotNull
public String name;
@SQLNotNull
public Timestamp endValidityTime = null;
@SQLNotNull
public String token;
@Column(nullable = false)
public Long parentId;
@Column(nullable = false)
public String name;
@Column(nullable = false)
public Timestamp endValidityTime = null;
@Column(nullable = false)
public String token;
}

View File

@ -3,6 +3,7 @@ package org.kar.archidata.model;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record GetToken(String jwt) {
public record GetToken(
String jwt) {
}

View File

@ -1,6 +1,6 @@
package org.kar.archidata.model;
public class Migration extends GenericTable{
public String migrationId;
public class Migration extends GenericTable {
public String migrationId;
}

View File

@ -3,46 +3,38 @@ package org.kar.archidata.model;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Token {
public Long id;
public Long userId;
public String token;
public String createTime;
public String endValidityTime;
public Token() {
}
public Token(long id, long userId, String token, String createTime, String endValidityTime) {
this.id = id;
this.userId = userId;
this.token = token;
this.createTime = createTime;
this.endValidityTime = endValidityTime;
}
public Token(ResultSet rs) {
int iii = 1;
try {
this.id = rs.getLong(iii++);
this.userId = rs.getLong(iii++);
this.token = rs.getString(iii++);
this.createTime = rs.getString(iii++);
this.endValidityTime = rs.getString(iii++);
} catch (SQLException ex) {
ex.printStackTrace();
}
}
@Override
public String toString() {
return "Token{" +
"id=" + id +
", userId=" + userId +
", token='" + token + '\'' +
", createTime=" + createTime +
", endValidityTime=" + endValidityTime +
'}';
}
public Long id;
public Long userId;
public String token;
public String createTime;
public String endValidityTime;
public Token() {}
public Token(long id, long userId, String token, String createTime, String endValidityTime) {
this.id = id;
this.userId = userId;
this.token = token;
this.createTime = createTime;
this.endValidityTime = endValidityTime;
}
public Token(ResultSet rs) {
int iii = 1;
try {
this.id = rs.getLong(iii++);
this.userId = rs.getLong(iii++);
this.token = rs.getString(iii++);
this.createTime = rs.getString(iii++);
this.endValidityTime = rs.getString(iii++);
} catch (SQLException ex) {
ex.printStackTrace();
}
}
@Override
public String toString() {
return "Token{" + "id=" + id + ", userId=" + userId + ", token='" + token + '\'' + ", createTime=" + createTime + ", endValidityTime=" + endValidityTime + '}';
}
}

View File

@ -15,35 +15,43 @@ CREATE TABLE `user` (
*/
import java.sql.Timestamp;
import java.util.List;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.sqlWrapper.Foreign;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("user")
import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Table(name = "user")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User extends GenericTable {
@SQLLimitSize(128)
public String login = null;
public Timestamp lastConnection = null;
@SQLDefault("'0'")
@SQLNotNull
public boolean admin = false;
@SQLDefault("'0'")
@SQLNotNull
public boolean blocked = false;
@SQLDefault("'0'")
@SQLNotNull
public boolean removed = false;
@Column(length = 128)
public String login = null;
public Timestamp lastConnection = null;
@SQLDefault("'0'")
@Column(nullable = false)
public boolean admin = false;
@SQLDefault("'0'")
@Column(nullable = false)
public boolean blocked = false;
@SQLDefault("'0'")
@Column(nullable = false)
public boolean removed = false;
@ManyToOne(fetch = FetchType.LAZY)
public List<Foreign<Data>> covers;
@Override
public String toString() {
return "User [login=" + login + ", last=" + lastConnection + ", admin=" + admin + "]";
return "User [login=" + this.login + ", last=" + this.lastConnection + ", admin=" + this.admin + "]";
}
}

View File

@ -3,7 +3,6 @@ package org.kar.archidata.model;
import java.util.HashMap;
import java.util.Map;
public class UserByToken {
public static final int TYPE_USER = -1;
public static final int TYPE_APPLICATION = -2;
@ -11,49 +10,49 @@ public class UserByToken {
public Integer type = null;
public Long id = null;
public Long parentId = null; // FOr application, this is the id of the application, and of user token, this is the USERID
public String name = null;
// Right map
public Map<String, Object> right = new HashMap<>();
public boolean hasRight(String key, Object value) {
if (! this.right.containsKey(key)) {
return false;
}
Object data = this.right.get(key);
if (data instanceof Boolean elem) {
if (value instanceof Boolean castVal) {
if (elem == castVal) {
return true;
}
}
return false;
}
if (data instanceof String elem) {
if (value instanceof String castVal) {
if (elem.equals(castVal)) {
return true;
}
}
return false;
}
if (data instanceof Long elem) {
if (value instanceof Long castVal) {
if (elem == castVal) {
return true;
}
}
return false;
}
if (data instanceof Double elem) {
if (value instanceof Double castVal) {
if (elem == castVal) {
return true;
}
}
return false;
}
return false;
}
public Long parentId = null; // FOr application, this is the id of the application, and of user token, this is the USERID
public String name = null;
// Right map
public Map<String, Object> right = new HashMap<>();
public boolean hasRight(String key, Object value) {
if (!this.right.containsKey(key)) {
return false;
}
Object data = this.right.get(key);
if (data instanceof Boolean elem) {
if (value instanceof Boolean castVal) {
if (elem == castVal) {
return true;
}
}
return false;
}
if (data instanceof String elem) {
if (value instanceof String castVal) {
if (elem.equals(castVal)) {
return true;
}
}
return false;
}
if (data instanceof Long elem) {
if (value instanceof Long castVal) {
if (elem == castVal) {
return true;
}
}
return false;
}
if (data instanceof Double elem) {
if (value instanceof Double castVal) {
if (elem == castVal) {
return true;
}
}
return false;
}
return false;
}
}

View File

@ -0,0 +1,16 @@
package org.kar.archidata.sqlWrapper;
public class Foreign<T> {
public final Long id;
public final T data;
public Foreign(final Long id) {
this.id = id;
this.data = null;
}
public Foreign(final T data) {
this.id = null;
this.data = data;
}
}

View File

@ -0,0 +1,11 @@
package org.kar.archidata.sqlWrapper;
import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalForeinKeyAsList;
import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalLink;
public class GenericAddOn {
public static void addGenericAddOn() {
SqlWrapper.addAddOn(new AddOnSQLTableExternalLink());
SqlWrapper.addAddOn(new AddOnSQLTableExternalForeinKeyAsList());
}
}

View File

@ -0,0 +1,43 @@
package org.kar.archidata.sqlWrapper;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
public class QuerryAnd implements QuerryItem {
protected final List<QuerryItem> childs;
public QuerryAnd(List<QuerryItem> childs) {
this.childs = childs;
}
public QuerryAnd(QuerryItem... items) {
this.childs = new ArrayList<>();
for (int iii = 0; iii < items.length; iii++) {
this.childs.add(items[iii]);
}
}
public void generateQuerry(StringBuilder querry, String tableName) {
querry.append(" (");
boolean first = false;
for (QuerryItem elem : this.childs) {
if (first) {
first = false;
} else {
querry.append(" AND ");
}
elem.generateQuerry(querry, tableName);
}
querry.append(")");
}
@Override
public int injectQuerry(PreparedStatement ps, int iii) throws Exception {
for (QuerryItem elem : this.childs) {
iii = elem.injectQuerry(ps, iii);
}
return iii;
}
}

View File

@ -0,0 +1,31 @@
package org.kar.archidata.sqlWrapper;
import java.sql.PreparedStatement;
public class QuerryCondition implements QuerryItem {
private final String key;
private final String comparator;
private final Object value;
public QuerryCondition(String key, String comparator, Object value) {
this.key = key;
this.comparator = comparator;
this.value = value;
}
public void generateQuerry(StringBuilder querry, String tableName) {
querry.append(tableName);
querry.append(".");
querry.append(this.key);
querry.append(" ");
querry.append(this.comparator);
querry.append(" ?");
}
@Override
public int injectQuerry(PreparedStatement ps, int iii) throws Exception {
SqlWrapper.addElement(ps, this.value, iii++);
return iii;
}
}

View File

@ -0,0 +1,9 @@
package org.kar.archidata.sqlWrapper;
import java.sql.PreparedStatement;
public interface QuerryItem {
void generateQuerry(StringBuilder querry, String tableName);
int injectQuerry(PreparedStatement ps, int iii) throws Exception;
}

View File

@ -0,0 +1,35 @@
package org.kar.archidata.sqlWrapper;
import java.sql.PreparedStatement;
import java.util.List;
public class QuerryOr implements QuerryItem {
protected final List<QuerryItem> childs;
public QuerryOr(List<QuerryItem> childs) {
this.childs = childs;
}
public void generateQuerry(StringBuilder querry, String tableName) {
querry.append(" (");
boolean first = false;
for (QuerryItem elem : this.childs) {
if (first) {
first = false;
} else {
querry.append(" OR ");
}
elem.generateQuerry(querry, tableName);
}
querry.append(")");
}
@Override
public int injectQuerry(PreparedStatement ps, int iii) throws Exception {
for (QuerryItem elem : this.childs) {
iii = elem.injectQuerry(ps, iii);
}
return iii;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,10 @@
package org.kar.archidata.sqlWrapper;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public interface SqlWrapperAddOn {
/**
@ -8,12 +12,14 @@ public interface SqlWrapperAddOn {
* @return The annotation class
*/
Class<?> getAnnotationClass();
/**
* Get the SQL type that is needed to declare for the specific Field Type.
* @param elem Field to declare.
* @return SQL type to create.
*/
String getSQLFieldType(Field elem);
/**
* Check if the field is manage by the local add-on
* @param elem Field to inspect.
@ -21,4 +27,17 @@ public interface SqlWrapperAddOn {
*/
boolean isCompatibleField(Field elem);
int insertData(PreparedStatement ps, Object data, int iii) throws SQLException;
// External mean that the type of the object is absolutely not obvious...
boolean isExternal();
int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List<StateLoad> autoClasify);
int fillFromQuerry(ResultSet rs, Field elem, Object data, int count) throws SQLException, IllegalArgumentException, IllegalAccessException;
boolean canUpdate();
void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List<String> ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception;
}

View File

@ -0,0 +1,5 @@
package org.kar.archidata.sqlWrapper;
public enum StateLoad {
DISABLE, NORMAL, ARRAY
}

View File

@ -1,8 +0,0 @@
package org.kar.archidata.sqlWrapper;
public record WhereCondition(
String key,
String comparator,
Object Value) {
}

View File

@ -0,0 +1,115 @@
package org.kar.archidata.sqlWrapper.addOn;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.kar.archidata.annotation.addOn.SQLTableExternalLink;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.SqlWrapperAddOn;
import org.kar.archidata.sqlWrapper.StateLoad;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AddOnSQLTableExternalForeinKeyAsList implements SqlWrapperAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnSQLTableExternalLink.class);
/**
* Convert the list if external id in a string '-' separated
* @param ids List of value (null are removed)
* @return '-' string separated
*/
protected static String getStringOfIds(List<Long> ids) {
List<Long> tmp = new ArrayList<>();
for (Long elem : ids) {
tmp.add(elem);
}
return tmp.stream().map(x -> String.valueOf(x)).collect(Collectors.joining("-"));
}
/**
* extract a list of "-" separated element from a SQL input data.
* @param rs Result Set of the BDD
* @param iii Id in the result set
* @return The list of Long value
* @throws SQLException if an error is generated in the sql request.
*/
protected static List<Long> getListOfIds(ResultSet rs, int iii) throws SQLException {
String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
List<Long> out = new ArrayList<>();
String[] elements = trackString.split("-");
for (String elem : elements) {
Long tmp = Long.parseLong(elem);
out.add(tmp);
}
return out;
}
@Override
public Class<?> getAnnotationClass() {
return SQLTableExternalLink.class;
}
public String getSQLFieldType(Field elem) {
return "STRING";
}
public boolean isCompatibleField(Field elem) {
SQLTableExternalLink decorators = elem.getDeclaredAnnotation(SQLTableExternalLink.class);
return decorators != null;
}
public int insertData(PreparedStatement ps, Object data, int iii) throws SQLException {
if (data == null) {
ps.setNull(iii++, Types.BIGINT);
} else {
@SuppressWarnings("unchecked")
String dataTmp = getStringOfIds((List<Long>) data);
ps.setString(iii++, dataTmp);
}
return iii++;
}
@Override
public boolean isExternal() {
// TODO Auto-generated method stub
return false;
}
@Override
public int generateQuerry(String tableName, Field elem, StringBuilder querry, String name, List<StateLoad> autoClasify) {
autoClasify.add(StateLoad.ARRAY);
querry.append(" ");
querry.append(tableName);
querry.append(".");
querry.append(name);
return 1;
}
@Override
public int fillFromQuerry(ResultSet rs, Field elem, Object data, int count) throws SQLException, IllegalArgumentException, IllegalAccessException {
List<Long> idList = getListOfIds(rs, count);
elem.set(data, idList);
return 1;
}
@Override
public boolean canUpdate() {
return true;
}
@Override
public void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List<String> ListOtherTables, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception {
// TODO Auto-generated method stub
SqlWrapper.createTablesSpecificType(tableName, elem, mainTableBuilder, ListOtherTables, createIfNotExist, createDrop, fieldId, String.class);
}
}

View File

@ -0,0 +1,265 @@
package org.kar.archidata.sqlWrapper.addOn;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.addOn.SQLTableExternalLink;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.SqlWrapper.ExceptionDBInterface;
import org.kar.archidata.sqlWrapper.SqlWrapperAddOn;
import org.kar.archidata.sqlWrapper.StateLoad;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AddOnSQLTableExternalLink implements SqlWrapperAddOn {
static final Logger LOGGER = LoggerFactory.getLogger(AddOnSQLTableExternalLink.class);
/**
* Convert the list if external id in a string '-' separated
* @param ids List of value (null are removed)
* @return '-' string separated
*/
protected static String getStringOfIds(final List<Long> ids) {
final List<Long> tmp = new ArrayList<>(ids);
return tmp.stream().map(String::valueOf).collect(Collectors.joining("-"));
}
/**
* extract a list of "-" separated element from a SQL input data.
* @param rs Result Set of the BDD
* @param iii Id in the result set
* @return The list of Long value
* @throws SQLException if an error is generated in the sql request.
*/
protected static List<Long> getListOfIds(final ResultSet rs, final int iii) throws SQLException {
final String trackString = rs.getString(iii);
if (rs.wasNull()) {
return null;
}
final List<Long> out = new ArrayList<>();
final String[] elements = trackString.split("-");
for (final String elem : elements) {
final Long tmp = Long.parseLong(elem);
out.add(tmp);
}
return out;
}
@Override
public Class<?> getAnnotationClass() {
return SQLTableExternalLink.class;
}
@Override
public String getSQLFieldType(final Field elem) {
return "STRING";
}
@Override
public boolean isCompatibleField(final Field elem) {
final SQLTableExternalLink decorators = elem.getDeclaredAnnotation(SQLTableExternalLink.class);
return decorators != null;
}
@Override
public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException {
if (data == null) {
ps.setNull(iii++, Types.BIGINT);
} else {
// TODO: we must check if the model of data in a list of Long ... !!!!
@SuppressWarnings("unchecked")
final String dataTmp = getStringOfIds((List<Long>) data);
ps.setString(iii++, dataTmp);
}
return iii++;
}
@Override
public boolean isExternal() {
// TODO Auto-generated method stub
return false;
}
@Override
public int generateQuerry(final String tableName, final Field elem, final StringBuilder querry, final String name, final List<StateLoad> autoClasify) {
autoClasify.add(StateLoad.ARRAY);
String localName = name;
if (name.endsWith("s")) {
localName = name.substring(0, name.length() - 1);
}
final String tmpVariable = "tmp_" + Integer.toString(autoClasify.size());
querry.append(" (SELECT GROUP_CONCAT(");
querry.append(tmpVariable);
querry.append(".");
querry.append(localName);
querry.append("_id SEPARATOR '-') FROM ");
querry.append(tableName);
querry.append("_link_");
querry.append(localName);
querry.append(" ");
querry.append(tmpVariable);
querry.append(" WHERE ");
querry.append(tmpVariable);
querry.append(".deleted = false AND ");
querry.append(tableName);
querry.append(".id = ");
querry.append(tmpVariable);
querry.append(".");
querry.append(tableName);
querry.append("_id GROUP BY ");
querry.append(tmpVariable);
querry.append(".");
querry.append(tableName);
querry.append("_id ) AS ");
querry.append(name);
querry.append(" ");
/*
" (SELECT GROUP_CONCAT(tmp.data_id SEPARATOR '-')" +
" FROM cover_link_node tmp" +
" WHERE tmp.deleted = false" +
" AND node.id = tmp.node_id" +
" GROUP BY tmp.node_id) AS covers" +
*/
return 1;
}
@Override
public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count) throws SQLException, IllegalArgumentException, IllegalAccessException {
throw new IllegalAccessException("This Add-on has not the capability to insert data directly in DB");
}
@Override
public boolean canUpdate() {
return false;
}
public static void addLink(final Class<?> clazz, final long localKey, final String table, final long remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
long uniqueSQLID = -1;
// real add in the BDD:
try {
// prepare the request:
final String querry = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + " VALUES (" + SqlWrapper.getDBNow() + ", "
+ SqlWrapper.getDBNow() + ", ?, ?)";
final PreparedStatement ps = entry.connection.prepareStatement(querry, Statement.RETURN_GENERATED_KEYS);
int iii = 1;
ps.setLong(iii++, localKey);
ps.setLong(iii++, remoteKey);
// execute the request
final int affectedRows = ps.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating data failed, no rows affected.");
}
// retrieve uid inserted
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
uniqueSQLID = generatedKeys.getLong(1);
} else {
throw new SQLException("Creating user failed, no ID obtained (1).");
}
} catch (final Exception ex) {
LOGGER.debug("Can not get the UID key inserted ... ");
ex.printStackTrace();
throw new SQLException("Creating user failed, no ID obtained (2).");
}
} catch (final SQLException ex) {
ex.printStackTrace();
throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage());
} finally {
entry.close();
entry = null;
}
}
public static void removeLink(final Class<?> clazz, final long localKey, final String table, final long remoteKey) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
final String querry = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=" + SqlWrapper.getDBNow() + ", `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table
+ "_id` = ?";
try {
final PreparedStatement ps = entry.connection.prepareStatement(querry);
int iii = 1;
ps.setLong(iii++, localKey);
ps.setLong(iii++, remoteKey);
ps.executeUpdate();
} catch (final SQLException ex) {
ex.printStackTrace();
throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage());
} finally {
entry.close();
entry = null;
}
}
@Override
public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List<String> ListOtherTables, final boolean createIfNotExist,
final boolean createDrop, final int fieldId) throws Exception {
final String name = elem.getName();
String localName = name;
if (name.endsWith("s")) {
localName = name.substring(0, name.length() - 1);
}
if (createIfNotExist && createDrop) {
final StringBuilder tableTmp = new StringBuilder();
tableTmp.append("DROP TABLE IF EXISTS `");
tableTmp.append(tableName);
tableTmp.append("_link_");
tableTmp.append(localName);
tableTmp.append("`;");
ListOtherTables.add(tableTmp.toString());
}
final StringBuilder otherTable = new StringBuilder();
otherTable.append("CREATE TABLE `");
otherTable.append(tableName);
otherTable.append("_link_");
otherTable.append(localName);
otherTable.append("`(\n");
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("\t\t`id` bigint NOT NULL AUTO_INCREMENT,\n");
otherTable.append("\t\t`deleted` tinyint(1) NOT NULL DEFAULT '0',\n");
otherTable.append("\t\t`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n");
otherTable.append("\t\t`modify_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n");
} else {
otherTable.append("\t\t`id` INTEGER PRIMARY KEY AUTOINCREMENT,\n");
otherTable.append("\t\t`deleted` INTEGER NOT NULL DEFAULT '0',\n");
otherTable.append("\t\t`create_date` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n");
otherTable.append("\t\t`modify_date` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,\n");
}
otherTable.append("\t\t`");
otherTable.append(tableName);
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("_id` bigint NOT NULL,\n");
} else {
otherTable.append("_id` INTEGER NOT NULL,\n");
}
otherTable.append("\t\t`");
otherTable.append(localName);
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("_id` bigint NOT NULL\n");
} else {
otherTable.append("_id` INTEGER NOT NULL\n");
}
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append("\t, PRIMARY KEY (`id`)\n");
}
otherTable.append("\t)");
if (!ConfigBaseVariable.getDBType().equals("sqlite")) {
otherTable.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n");
}
otherTable.append(";");
ListOtherTables.add(otherTable.toString());
}
}

View File

@ -1,21 +0,0 @@
package org.kar.archidata.sqlWrapper.addOn;
import java.lang.reflect.Field;
import org.kar.archidata.annotation.SQLTableLinkGeneric;
import org.kar.archidata.sqlWrapper.SqlWrapperAddOn;
public class ExternalLink implements SqlWrapperAddOn {
@Override
public Class<?> getAnnotationClass() {
return SQLTableLinkGeneric.class;
}
public String getSQLFieldType(Field elem) {
return "STRING";
}
public boolean isCompatibleField(Field elem) {
SQLTableLinkGeneric decorators = elem.getDeclaredAnnotation(SQLTableLinkGeneric.class);
return decorators != null;
}
}

View File

@ -1,92 +1,94 @@
package org.kar.archidata.util;
public class ConfigBaseVariable {
static public String tmpDataFolder = System.getenv("DATA_TMP_FOLDER");
static public String dataFolder = System.getenv("DATA_FOLDER");
static public String dbType = System.getenv("DB_TYPE");
static public String dbHost = System.getenv("DB_HOST");
static public String dbPort = System.getenv("DB_PORT");
static public String dbUser = System.getenv("DB_USER");
static public String dbKeepConnected = System.getenv("DB_KEEP_CONNECTED");
static public String dbPassword = System.getenv("DB_PASSWORD");
static public String bdDatabase = System.getenv("DB_DATABASE");
static public String apiAdress = System.getenv("API_ADDRESS");
static public String ssoAdress = System.getenv("SSO_ADDRESS");
static public String ssoToken = System.getenv("SSO_TOKEN");
public static String getTmpDataFolder() {
if (tmpDataFolder == null) {
return "/application/data/tmp";
}
return tmpDataFolder;
}
public static String getMediaDataFolder() {
if (dataFolder == null) {
return "/application/data/media";
}
return dataFolder;
}
public static String getDBType() {
if (dbType == null) {
return "mysql";
}
return dbType;
}
public static String getDBHost() {
if (dbHost == null) {
return "localhost";
}
return dbHost;
}
public static String getDBPort() {
if (dbPort == null) {
return "3306";
}
return dbPort;
}
public static String getDBLogin() {
if (dbUser == null) {
return "root";
}
return dbUser;
}
public static String getDBPassword() {
if (dbPassword == null) {
return "base_db_password";
}
return dbPassword;
}
public static String getDBName() {
if (bdDatabase == null) {
return "unknown";
}
return bdDatabase;
}
public static boolean getDBKeepConnected() {
if (dbKeepConnected == null) {
return false;
}
return Boolean.parseBoolean(dbKeepConnected);
}
public static String getlocalAddress() {
if (apiAdress == null) {
return "http://0.0.0.0:80/api/";
}
return apiAdress;
}
public static String getSSOAddress() {
return ssoAdress;
}
public static String ssoToken() {
return ssoToken;
}
static public String tmpDataFolder = System.getenv("DATA_TMP_FOLDER");
static public String dataFolder = System.getenv("DATA_FOLDER");
static public String dbType = System.getenv("DB_TYPE");
static public String dbHost = System.getenv("DB_HOST");
static public String dbPort = System.getenv("DB_PORT");
static public String dbUser = System.getenv("DB_USER");
static public String dbKeepConnected = System.getenv("DB_KEEP_CONNECTED");
static public String dbPassword = System.getenv("DB_PASSWORD");
static public String bdDatabase = System.getenv("DB_DATABASE");
static public String apiAdress = System.getenv("API_ADDRESS");
static public String ssoAdress = System.getenv("SSO_ADDRESS");
static public String ssoToken = System.getenv("SSO_TOKEN");
public static String getTmpDataFolder() {
if (tmpDataFolder == null) {
return "/application/data/tmp";
}
return tmpDataFolder;
}
public static String getMediaDataFolder() {
if (dataFolder == null) {
return "/application/data/media";
}
return dataFolder;
}
public static String getDBType() {
if (dbType == null) {
return "mysql";
}
return dbType;
}
public static String getDBHost() {
if (dbHost == null) {
return "localhost";
}
return dbHost;
}
public static String getDBPort() {
if (dbPort == null) {
return "3306";
}
return dbPort;
}
public static String getDBLogin() {
if (dbUser == null) {
return "root";
}
return dbUser;
}
public static String getDBPassword() {
if (dbPassword == null) {
return "base_db_password";
}
return dbPassword;
}
public static String getDBName() {
if (bdDatabase == null) {
return "unknown";
}
return bdDatabase;
}
public static boolean getDBKeepConnected() {
if (dbKeepConnected == null) {
return false;
}
return Boolean.parseBoolean(dbKeepConnected);
}
public static String getlocalAddress() {
if (apiAdress == null) {
return "http://0.0.0.0:80/api/";
}
return apiAdress;
}
public static String getSSOAddress() {
return ssoAdress;
}
public static String ssoToken() {
return ssoToken;
}
}

View File

@ -11,283 +11,283 @@ import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import jakarta.ws.rs.core.Response;
import java.util.List;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.model.Data;
import org.kar.archidata.sqlWrapper.QuerryAnd;
import org.kar.archidata.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalLink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.Response;
public class DataTools {
static final Logger logger = LoggerFactory.getLogger(DataTools.class);
public final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/**
* Upload some data
*/
private static long tmpFolderId = 1;
public static void createFolder(String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
logger.info("Create folder: " + path);
Files.createDirectories(java.nio.file.Path.of(path));
}
}
public static long getTmpDataId() {
return tmpFolderId++;
}
public static String getTmpFileInData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getTmpFolder() {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static Data getWithSha512(String sha512) {
try {
return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512);
private final static Logger LOGGER = LoggerFactory.getLogger(DataTools.class);
public final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/**
* Upload some data
*/
private static long tmpFolderId = 1;
public static void createFolder(String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
LOGGER.info("Create folder: " + path);
Files.createDirectories(java.nio.file.Path.of(path));
}
}
public static long getTmpDataId() {
return tmpFolderId++;
}
public static String getTmpFileInData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getTmpFolder() {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static Data getWithSha512(String sha512) {
try {
return SqlWrapper.getWhere(Data.class, new QuerryCondition("sha512", "=", sha512));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Data getWithId(long id) {
try {
return SqlWrapper.getWhere(Data.class, "deleted", "=", false, "id", "=", id);
return null;
}
public static Data getWithId(long id) {
try {
return SqlWrapper.getWhere(Data.class, new QuerryAnd(List.of(new QuerryCondition("deleted", "=", false), new QuerryCondition("id", "=", id))));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException, SQLException {
// determine mime type:
String mimeType = "";
String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
switch (extension.toLowerCase()) {
case "jpg":
case "jpeg":
mimeType = "image/jpeg";
break;
case "png":
mimeType = "image/png";
break;
case "webp":
mimeType = "image/webp";
break;
case "mka":
mimeType = "audio/x-matroska";
break;
case "mkv":
mimeType = "video/x-matroska";
break;
case "webm":
mimeType = "video/webm";
break;
default:
throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}
String tmpPath = getTmpFileInData(tmpUID);
long fileSize = Files.size(Paths.get(tmpPath));
Data out = new Data();;
try {
out.sha512 = sha512;
out.mimeType = mimeType;
out.size = fileSize;
out = SqlWrapper.insert(out);
} catch (SQLException ex) {
ex.printStackTrace();
return null;
} catch (Exception e) {
return null;
}
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException, SQLException {
// determine mime type:
String mimeType = "";
String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
switch (extension.toLowerCase()) {
case "jpg":
case "jpeg":
mimeType = "image/jpeg";
break;
case "png":
mimeType = "image/png";
break;
case "webp":
mimeType = "image/webp";
break;
case "mka":
mimeType = "audio/x-matroska";
break;
case "mkv":
mimeType = "video/x-matroska";
break;
case "webm":
mimeType = "video/webm";
break;
default:
throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}
String tmpPath = getTmpFileInData(tmpUID);
long fileSize = Files.size(Paths.get(tmpPath));
Data out = new Data();
;
try {
out.sha512 = sha512;
out.mimeType = mimeType;
out.size = fileSize;
out = SqlWrapper.insert(out);
} catch (SQLException ex) {
ex.printStackTrace();
return null;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
return null;
}
String mediaPath = getFileData(out.id);
logger.info("src = {}", tmpPath);
logger.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
logger.info("Move done");
// all is done the file is correctly installed...
return out;
}
public static void undelete(Long id) {
String mediaPath = getFileData(out.id);
LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
LOGGER.info("Move done");
// all is done the file is correctly installed...
return out;
}
public static void undelete(Long id) {
try {
SqlWrapper.unsetDelete(Data.class, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
return saveFile(uploadedInputStream, getTmpFileInData(idData));
}
public static void removeTemporaryFile(long idData) {
String filepath = getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (IOException e) {
logger.info("can not delete temporary file : {}", Paths.get(filepath));
e.printStackTrace();
}
}
}
// save uploaded file to a defined location on the server
public static String saveFile(InputStream uploadedInputStream, String serverLocation) {
String out = "";
try {
OutputStream outpuStream = new FileOutputStream(new File(
serverLocation));
int read = 0;
byte[] bytes = new byte[CHUNK_SIZE_IN];
MessageDigest md = MessageDigest.getInstance("SHA-512");
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
//logger.debug("write {}", read);
md.update(bytes, 0, read);
outpuStream.write(bytes, 0, read);
}
logger.info("Flush input stream ... {}", serverLocation);
outpuStream.flush();
outpuStream.close();
// create the end of sha512
byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (IOException ex) {
logger.error("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (NoSuchAlgorithmException ex) {
logger.error("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
// curl http://localhost:9993/api/users/3
//@Secured
/*
@GET
@Path("{id}")
//@RolesAllowed("GUEST")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveData(@HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
return retriveDataFull(range, id, "no-name");
}
*/
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
return saveFile(uploadedInputStream, getTmpFileInData(idData));
}
public static void removeTemporaryFile(long idData) {
String filepath = getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (IOException e) {
LOGGER.info("can not delete temporary file : {}", Paths.get(filepath));
e.printStackTrace();
}
}
}
// save uploaded file to a defined location on the server
public static String saveFile(InputStream uploadedInputStream, String serverLocation) {
String out = "";
try {
OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[CHUNK_SIZE_IN];
MessageDigest md = MessageDigest.getInstance("SHA-512");
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
//logger.debug("write {}", read);
md.update(bytes, 0, read);
outpuStream.write(bytes, 0, read);
}
LOGGER.info("Flush input stream ... {}", serverLocation);
outpuStream.flush();
outpuStream.close();
// create the end of sha512
byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (IOException ex) {
LOGGER.error("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (NoSuchAlgorithmException ex) {
LOGGER.error("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
// curl http://localhost:9993/api/users/3
//@Secured
/*
@GET
@Path("{id}")
//@RolesAllowed("GUEST")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveData(@HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
return retriveDataFull(range, id, "no-name");
}
*/
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static String multipartCorrection(String data) {
if (data == null) {
return null;
}
if (data.isEmpty()) {
return null;
}
if (data.contentEquals("null")) {
return null;
}
return data;
}
public static <T> Response uploadCover(Class<T> clazz,
Long id,
String fileName,
InputStream fileInputStream,
FormDataContentDisposition fileMetaData
) {
try {
// correct input string stream :
fileName = multipartCorrection(fileName);
//public NodeSmall uploadFile(final FormDataMultiPart form) {
logger.info("Upload media file: {}", fileMetaData);
logger.info(" - id: {}", id);
logger.info(" - file_name: ", fileName);
logger.info(" - fileInputStream: {}", fileInputStream);
logger.info(" - fileMetaData: {}", fileMetaData);
T media = SqlWrapper.get(clazz, id);
if (media == null) {
return Response.notModified("Media Id does not exist or removed...").build();
}
long tmpUID = getTmpDataId();
String sha512 = saveTemporaryFile(fileInputStream, tmpUID);
Data data = getWithSha512(sha512);
if (data == null) {
logger.info("Need to add the data in the BDD ... ");
try {
data = createNewData(tmpUID, fileName, sha512);
} catch (IOException ex) {
removeTemporaryFile(tmpUID);
ex.printStackTrace();
return Response.notModified("can not create input media").build();
} catch (SQLException ex) {
ex.printStackTrace();
removeTemporaryFile(tmpUID);
return Response.notModified("Error in SQL insertion ...").build();
}
} else if (data.deleted == true) {
logger.error("Data already exist but deleted");
undelete(data.id);
data.deleted = false;
} else {
logger.error("Data already exist ... all good");
}
// Fist step: retrieve all the Id of each parents:...
logger.info("Find typeNode");
SqlWrapper.addLink(clazz, id, "cover", data.id);
return Response.ok(SqlWrapper.get(clazz, id)).build();
} catch (Exception ex) {
System.out.println("Cat ann unexpected error ... ");
ex.printStackTrace();
}
return Response.serverError().build();
}
if (data == null) {
return null;
}
if (data.isEmpty()) {
return null;
}
if (data.contentEquals("null")) {
return null;
}
return data;
}
public static <T> Response uploadCover(Class<T> clazz, Long id, String fileName, InputStream fileInputStream, FormDataContentDisposition fileMetaData) {
try {
// correct input string stream :
fileName = multipartCorrection(fileName);
//public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload media file: {}", fileMetaData);
LOGGER.info(" - id: {}", id);
LOGGER.info(" - file_name: ", fileName);
LOGGER.info(" - fileInputStream: {}", fileInputStream);
LOGGER.info(" - fileMetaData: {}", fileMetaData);
T media = SqlWrapper.get(clazz, id);
if (media == null) {
return Response.notModified("Media Id does not exist or removed...").build();
}
long tmpUID = getTmpDataId();
String sha512 = saveTemporaryFile(fileInputStream, tmpUID);
Data data = getWithSha512(sha512);
if (data == null) {
LOGGER.info("Need to add the data in the BDD ... ");
try {
data = createNewData(tmpUID, fileName, sha512);
} catch (IOException ex) {
removeTemporaryFile(tmpUID);
ex.printStackTrace();
return Response.notModified("can not create input media").build();
} catch (SQLException ex) {
ex.printStackTrace();
removeTemporaryFile(tmpUID);
return Response.notModified("Error in SQL insertion ...").build();
}
} else if (data.deleted == true) {
LOGGER.error("Data already exist but deleted");
undelete(data.id);
data.deleted = false;
} else {
LOGGER.error("Data already exist ... all good");
}
// Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode");
AddOnSQLTableExternalLink.addLink(clazz, id, "cover", data.id);
return Response.ok(SqlWrapper.get(clazz, id)).build();
} catch (Exception ex) {
System.out.println("Cat ann unexpected error ... ");
ex.printStackTrace();
}
return Response.serverError().build();
}
}

View File

@ -32,53 +32,54 @@ public class JWTWrapper {
private static RSAKey rsaJWK = null;;
private static RSAKey rsaPublicJWK = null;
public static class PublicKey {
public String key;
public PublicKey(String key) {
this.key = key;
}
public PublicKey() {
}
public PublicKey() {}
}
public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException {
// check Token:
URL obj = new URL(ssoUri + "public_key");
//logger.debug("Request token from: {}", obj);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", application);
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
String ssoToken = ConfigBaseVariable.ssoToken();
if (ssoToken != null) {
con.setRequestProperty("Authorization", "Zota " + ssoToken);
}
int responseCode = con.getResponseCode();
//logger.debug("GET Response Code :: {}", responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { // success
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
//logger.debug(response.toString());
ObjectMapper mapper = new ObjectMapper();
PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
rsaPublicJWK = RSAKey.parse(values.key);
return;
}
logger.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj);
}
public static void initLocalToken(String baseUUID) throws Exception{
public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException {
// check Token:
URL obj = new URL(ssoUri + "public_key");
//logger.debug("Request token from: {}", obj);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", application);
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
String ssoToken = ConfigBaseVariable.ssoToken();
if (ssoToken != null) {
con.setRequestProperty("Authorization", "Zota " + ssoToken);
}
int responseCode = con.getResponseCode();
//logger.debug("GET Response Code :: {}", responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { // success
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
//logger.debug(response.toString());
ObjectMapper mapper = new ObjectMapper();
PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
rsaPublicJWK = RSAKey.parse(values.key);
return;
}
logger.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj);
}
public static void initLocalToken(String baseUUID) throws Exception {
// RSA signatures require a public and private RSA key pair, the public key
// must be made known to the JWS recipient in order to verify the signatures
try {
@ -111,12 +112,14 @@ public class JWTWrapper {
}
}
public static String getPublicKeyJson() {
if (rsaPublicJWK == null) {
return null;
}
return rsaPublicJWK.toJSONString();
}
public static java.security.interfaces.RSAPublicKey getPublicKeyJava() throws JOSEException {
if (rsaPublicJWK == null) {
return null;
@ -146,21 +149,16 @@ public class JWTWrapper {
*/
try {
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaJWK);
logger.warn("timeOutInMunites= {}", timeOutInMunites);
Date now = new Date();
logger.warn("now = {}", now);
Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
logger.warn("expiration= {}", expiration);
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder()
.subject(Long.toString(userID))
.claim("login", userLogin)
.claim("application", application)
.issuer(isuer)
.issueTime(now)
.expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning
JWSSigner signer = new RSASSASigner(rsaJWK);
logger.warn("timeOutInMunites= {}", timeOutInMunites);
Date now = new Date();
logger.warn("now = {}", now);
Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
logger.warn("expiration= {}", expiration);
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
.expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning
// add right if needed:
if (rights != null && !rights.isEmpty()) {
builder.claim("right", rights);
@ -168,7 +166,7 @@ public class JWTWrapper {
// Prepare JWT with claims set
JWTClaimsSet claimsSet = builder.build();
SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
// Compute the RSA signature
signedJWT.sign(signer);
// serialize the output...
@ -178,7 +176,7 @@ public class JWTWrapper {
}
return null;
}
public static JWTClaimsSet validateToken(String signedToken, String isuer, String application) {
if (rsaPublicJWK == null) {
logger.warn("JWT public key is not present !!!");
@ -187,18 +185,18 @@ public class JWTWrapper {
try {
// On the consumer side, parse the JWS and verify its RSA signature
SignedJWT signedJWT = SignedJWT.parse(signedToken);
JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
if (!signedJWT.verify(verifier)) {
logger.error("JWT token is NOT verified ");
return null;
}
if (!new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime())) {
logger.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime() );
logger.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime());
return null;
}
if (!isuer.equals(signedJWT.getJWTClaimsSet().getIssuer())) {
logger.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'" );
logger.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
return null;
}
if (application != null) {

View File

@ -1,9 +1,8 @@
package org.kar.archidata.util;
public class PublicKey {
public String key;
public PublicKey(String key) {
this.key = key;
}

View File

@ -31,6 +31,7 @@ public class RESTApi {
public void setToken(String token) {
this.token = token;
}
public <T> List<T> gets(Class<T> clazz, String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
@ -44,9 +45,10 @@ public class RESTApi {
RESTErrorResponseExeption out = mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class);
throw out;
}
List<T> out = mapper.readValue(httpResponse.body(), new TypeReference<List<T>>(){});
List<T> out = mapper.readValue(httpResponse.body(), new TypeReference<List<T>>() {});
return out;
}
public <T> T get(Class<T> clazz, String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
@ -59,20 +61,21 @@ public class RESTApi {
if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) {
//LOGGER.error("catch error from REST API: {}", httpResponse.body());
RESTErrorResponseExeption out = mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class);
throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status,out.statusMessage);
throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage);
}
//LOGGER.error("status code: {}", httpResponse.statusCode());
//LOGGER.error("data: {}", httpResponse.body());
if (clazz.equals(String.class)) {
return (T)httpResponse.body();
return (T) httpResponse.body();
}
T out = mapper.readValue(httpResponse.body(), clazz);
return out;
}
public <T, U> T post(Class<T> clazz, String urlOffset, U data) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
String body = mapper.writeValueAsString(data);
String body = mapper.writeValueAsString(data);
Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset));
if (token != null) {
requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token);
@ -87,15 +90,16 @@ public class RESTApi {
throw out;
}
if (clazz.equals(String.class)) {
return (T)httpResponse.body();
return (T) httpResponse.body();
}
T out = mapper.readValue(httpResponse.body(), clazz);
return out;
}
public <T> T postMap(Class<T> clazz, String urlOffset, Map<String, Object> data) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
String body = mapper.writeValueAsString(data);
String body = mapper.writeValueAsString(data);
Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset));
if (token != null) {
requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token);
@ -108,15 +112,16 @@ public class RESTApi {
throw out;
}
if (clazz.equals(String.class)) {
return (T)httpResponse.body();
return (T) httpResponse.body();
}
T out = mapper.readValue(httpResponse.body(), clazz);
return out;
}
public <T, U> T put(Class<T> clazz, String urlOffset, U data) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
String body = mapper.writeValueAsString(data);
String body = mapper.writeValueAsString(data);
Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset));
if (token != null) {
requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token);
@ -129,15 +134,16 @@ public class RESTApi {
throw out;
}
if (clazz.equals(String.class)) {
return (T)httpResponse.body();
return (T) httpResponse.body();
}
T out = mapper.readValue(httpResponse.body(), clazz);
return out;
}
public <T> T putMap(Class<T> clazz, String urlOffset, Map<String, Object> data) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
String body = mapper.writeValueAsString(data);
String body = mapper.writeValueAsString(data);
Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset));
if (token != null) {
requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + token);
@ -150,11 +156,12 @@ public class RESTApi {
throw out;
}
if (clazz.equals(String.class)) {
return (T)httpResponse.body();
return (T) httpResponse.body();
}
T out = mapper.readValue(httpResponse.body(), clazz);
return out;
}
public <T, U> T delete(Class<T> clazz, String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException {
ObjectMapper mapper = new ObjectMapper();
HttpClient client = HttpClient.newHttpClient();
@ -169,7 +176,7 @@ public class RESTApi {
throw out;
}
if (clazz.equals(String.class)) {
return (T)httpResponse.body();
return (T) httpResponse.body();
}
T out = mapper.readValue(httpResponse.body(), clazz);
return out;

View File

@ -0,0 +1,44 @@
package test.kar.archidata;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.util.RESTApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestBase {
final static Logger logger = LoggerFactory.getLogger(TestBase.class);
static RESTApi api = null;
@BeforeAll
public static void configureWebServer() throws Exception {
logger.info("Create DB");
final String dbName = "sdfsdfsdfsfsdfsfsfsfsdfsdfsd";
boolean data = SqlWrapper.isDBExist(dbName);
logger.error("exist: {}", data);
data = SqlWrapper.createDB(dbName);
logger.error("create: {}", data);
data = SqlWrapper.isDBExist(dbName);
logger.error("exist: {}", data);
}
@AfterAll
public static void stopWebServer() throws InterruptedException {
logger.info("Kill the web server");
// TODO: do it better...
}
@Order(1)
@Test
public void checkSimpleTestError() throws Exception {
Assertions.assertEquals("lkjlkjlkjlk", "alive and kicking");
}
}