[DEV] review many models and system
This commit is contained in:
parent
99cca8bebf
commit
d8c6de7bde
7
.checkstyle
Normal file
7
.checkstyle
Normal 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>
|
30
.classpath
30
.classpath
@ -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
1
conditioningUnit
Normal file
@ -0,0 +1 @@
|
||||
[]
|
13
pom.xml
13
pom.xml
@ -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>
|
||||
|
@ -16,3 +16,4 @@ public class GlobalConfiguration {
|
||||
ConfigBaseVariable.getDBKeepConnected());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
129
src/org/kar/archidata/annotation/AnnotationTools.java
Normal file
129
src/org/kar/archidata/annotation/AnnotationTools.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,6 @@ import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLCreateTime {
|
||||
|
||||
public @interface CreationTimestamp {
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ import java.lang.annotation.Target;
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLComment {
|
||||
|
||||
|
||||
String value();
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import java.lang.annotation.Target;
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLDefault {
|
||||
|
||||
|
||||
String value();
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLDeleted {
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLIfNotExists {
|
||||
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -8,5 +8,5 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLNotRead {
|
||||
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
@ -7,6 +7,6 @@ import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SQLAutoIncrement {
|
||||
|
||||
public @interface UpdateTimestamp {
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
}
|
@ -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 {}
|
||||
|
@ -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 {}
|
||||
|
@ -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 {}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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") );
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.kar.archidata.migration;
|
||||
|
||||
public class MigrationException extends Exception {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 20230502L;
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 = "";
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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 + '}';
|
||||
}
|
||||
}
|
||||
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
16
src/org/kar/archidata/sqlWrapper/Foreign.java
Normal file
16
src/org/kar/archidata/sqlWrapper/Foreign.java
Normal 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;
|
||||
}
|
||||
}
|
11
src/org/kar/archidata/sqlWrapper/GenericAddOn.java
Normal file
11
src/org/kar/archidata/sqlWrapper/GenericAddOn.java
Normal 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());
|
||||
}
|
||||
}
|
43
src/org/kar/archidata/sqlWrapper/QuerryAnd.java
Normal file
43
src/org/kar/archidata/sqlWrapper/QuerryAnd.java
Normal 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;
|
||||
}
|
||||
}
|
31
src/org/kar/archidata/sqlWrapper/QuerryCondition.java
Normal file
31
src/org/kar/archidata/sqlWrapper/QuerryCondition.java
Normal 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;
|
||||
}
|
||||
}
|
9
src/org/kar/archidata/sqlWrapper/QuerryItem.java
Normal file
9
src/org/kar/archidata/sqlWrapper/QuerryItem.java
Normal 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;
|
||||
}
|
35
src/org/kar/archidata/sqlWrapper/QuerryOr.java
Normal file
35
src/org/kar/archidata/sqlWrapper/QuerryOr.java
Normal 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
@ -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;
|
||||
|
||||
}
|
||||
|
5
src/org/kar/archidata/sqlWrapper/StateLoad.java
Normal file
5
src/org/kar/archidata/sqlWrapper/StateLoad.java
Normal file
@ -0,0 +1,5 @@
|
||||
package org.kar.archidata.sqlWrapper;
|
||||
|
||||
public enum StateLoad {
|
||||
DISABLE, NORMAL, ARRAY
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package org.kar.archidata.sqlWrapper;
|
||||
|
||||
public record WhereCondition(
|
||||
String key,
|
||||
String comparator,
|
||||
Object Value) {
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -1,9 +1,8 @@
|
||||
package org.kar.archidata.util;
|
||||
|
||||
|
||||
public class PublicKey {
|
||||
public String key;
|
||||
|
||||
|
||||
public PublicKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
@ -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;
|
||||
|
44
test/src/test/kar/archidata/TestBase.java
Normal file
44
test/src/test/kar/archidata/TestBase.java
Normal 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");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user