diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..3bf4578 --- /dev/null +++ b/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..c4e3f9b --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + achi-data + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/CheckStyle.xml b/CheckStyle.xml new file mode 100755 index 0000000..d68aedd --- /dev/null +++ b/CheckStyle.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CleanUp.xml b/CleanUp.xml new file mode 100644 index 0000000..9df98d2 --- /dev/null +++ b/CleanUp.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Formatter.xml b/Formatter.xml new file mode 100644 index 0000000..b775e22 --- /dev/null +++ b/Formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a9d1e81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,6 @@ +PROPIETARY licence +================== + +Copyright at Edouard DUPIN + +you have no right \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..54d39e2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,177 @@ + + 4.0.0 + kar + archidata + 0.1.0 + + 2.1 + 2.32 + 2.3.1 + 3.0.7 + + 3.1 + 17 + 17 + + 3.1.1 + + + + + + + org.glassfish.jersey + jersey-bom + ${jersey.version} + pom + import + + + + + + + + org.glassfish.jersey.media + jersey-media-multipart + + + org.glassfish.jersey.inject + jersey-hk2 + + + org.glassfish.jersey.containers + jersey-container-grizzly2-http + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + javax.ws.rs + javax.ws.rs-api + 2.1.1 + + + com.sun.xml.bind + jaxb-impl + ${jaxb.version} + + + com.sun.istack + istack-commons-runtime + ${istack.version} + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-grizzly2 + test + + + mysql + mysql-connector-java + 8.0.30 + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + com.fasterxml.jackson.core + jackson-databind + 2.8.10 + + + javax.servlet + javax.servlet-api + 3.0.1 + compile + + + org.jetbrains + annotations + RELEASE + compile + + + com.nimbusds + nimbus-jose-jwt + 9.22 + + + + + src + test/src + ${project.basedir}/out/maven/ + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + maven-assembly-plugin + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + private + true + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + public + + + + + + \ No newline at end of file diff --git a/src/org/kar/archidata/GlobalConfiguration.java b/src/org/kar/archidata/GlobalConfiguration.java new file mode 100644 index 0000000..7e18866 --- /dev/null +++ b/src/org/kar/archidata/GlobalConfiguration.java @@ -0,0 +1,16 @@ +package org.kar.archidata; + +import org.kar.archidata.db.DBConfig; +import org.kar.archidata.util.ConfigBaseVariable; + +public class GlobalConfiguration { + public static DBConfig dbConfig = null;; + + static { + dbConfig = new DBConfig(ConfigBaseVariable.getDBHost(), + Integer.parseInt(ConfigBaseVariable.getDBPort()), + ConfigBaseVariable.getDBLogin(), + ConfigBaseVariable.getDBPassword(), + ConfigBaseVariable.getDBName()); + } +} diff --git a/src/org/kar/archidata/SqlWrapper.java b/src/org/kar/archidata/SqlWrapper.java new file mode 100644 index 0000000..5aafed9 --- /dev/null +++ b/src/org/kar/archidata/SqlWrapper.java @@ -0,0 +1,1205 @@ +package org.kar.archidata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.sql.*; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import org.kar.archidata.annotation.SQLAutoIncrement; +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.SQLNotRead; +import org.kar.archidata.annotation.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLTableLinkGeneric; +import org.kar.archidata.annotation.SQLTableLinkGeneric.ModelLink; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.annotation.SQLUpdateTime; +import org.kar.archidata.db.DBEntry; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.kar.archidata.annotation.SQLCreateTime; +import org.kar.archidata.annotation.SQLDefault; + + +public class SqlWrapper { + + public static class ExceptionDBInterface extends Exception { + public int errorID; + ExceptionDBInterface(int errorId, String message) { + super(message); + this.errorID = errorId; + } + } + + public SqlWrapper() { + + } + + public static String convertTypeInSQL(Class type) throws Exception { + if (type == Long.class || type == long.class ) { + return "bigint"; + } + if (type == Integer.class || type == int.class ) { + return "int"; + } + if (type == Boolean.class || type == boolean.class) { + return "tinyint(1)"; + } + if (type == Float.class || type == float.class) { + return "float"; + } + if (type == Double.class || type == double.class) { + return "double"; + } + if (type == Timestamp.class) { + return "timestamp(3)"; + } + if (type == Date.class) { + return "date"; + } + if (type == String.class) { + return "text"; + } + throw new Exception("Imcompatible type of element in object for: " + type.getCanonicalName()); + } + + protected static void setValuedb(Class type, T data, int index, Field field, PreparedStatement ps) throws IllegalArgumentException, IllegalAccessException, SQLException { + if (type == Long.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.BIGINT); + } else { + ps.setLong(index++, (Long)tmp); + } + } else if (type == long.class ) { + ps.setLong(index++, field.getLong(data)); + } else if (type == Integer.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setInt(index++, (Integer)tmp); + } + } else if (type == int.class ) { + ps.setInt(index++, field.getInt(data)); + } else if (type == Float.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.FLOAT); + } else { + ps.setFloat(index++, (Float)tmp); + } + } else if (type == float.class) { + ps.setFloat(index++, field.getFloat(data)); + } else if (type == Double.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.DOUBLE); + } else { + ps.setDouble(index++, (Double)tmp); + } + } else if (type == Double.class) { + ps.setDouble(index++, field.getDouble(data)); + } else if (type == Boolean.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setBoolean(index++, (Boolean)tmp); + } + } else if (type == boolean.class) { + ps.setBoolean(index++, field.getBoolean(data)); + } else if (type == Timestamp.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setTimestamp(index++, (Timestamp)tmp); + } + } else if (type == Date.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setDate(index++, (Date)tmp); + } + } else if (type == String.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.VARCHAR); + } else { + ps.setString(index++, (String)tmp); + } + } + } + protected static void setValueFromDb(Class type, T data, int index, Field field, ResultSet rs) throws IllegalArgumentException, IllegalAccessException, SQLException { + if (type == Long.class) { + Long tmp = rs.getLong(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + //System.out.println(" ==> " + tmp); + field.set(data, tmp); + } + } else if (type == long.class ) { + Long tmp = rs.getLong(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setLong(data, tmp); + } + } else if (type == Integer.class) { + Integer tmp = rs.getInt(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == int.class ) { + Integer tmp = rs.getInt(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setInt(data, tmp); + } + } else if (type == Float.class) { + Float tmp = rs.getFloat(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == float.class) { + Float tmp = rs.getFloat(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setFloat(data, tmp); + } + } else if (type == Double.class) { + Double tmp = rs.getDouble(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == double.class) { + Double tmp = rs.getDouble(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setDouble(data, tmp); + } + } else if (type == Boolean.class) { + Boolean tmp = rs.getBoolean(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == boolean.class) { + Boolean tmp = rs.getBoolean(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setBoolean(data, tmp); + } + } else if (type == Timestamp.class) { + Timestamp tmp = rs.getTimestamp(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == Date.class) { + Date tmp = rs.getDate(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == String.class) { + String tmp = rs.getString(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } + } + public static ModelLink getLinkMode(Field elem) { + SQLTableLinkGeneric[] decorators = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class); + if (decorators == null || decorators.length == 0) { + return SQLTableLinkGeneric.ModelLink.NONE; + } + return decorators[0].value(); + } + + public static T insert(T data) throws Exception { + Class clazz = data.getClass(); + //public static NodeSmall createNode(String typeInNode, String name, String descrition, Long parentId) { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("INSERT INTO "); + query.append(tableName); + query.append(" ("); + + boolean firstField = true; + int count = 0; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + continue; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + if (!elem.getClass().isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + count++; + String name = elem.getName(); + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("`"); + } + firstField = true; + query.append(") VALUES ("); + for (int iii = 0; iii type = elem.getType(); + if (!type.isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + setValuedb(type, data, iii++, elem, ps); + } else { + // transform the data in string to insert it ... + Object tmp = elem.get(data); + if (tmp == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + @SuppressWarnings("unchecked") + String dataTmp = getStringOfIds((List)tmp); + ps.setString(iii++, dataTmp); + } + } + count++; + } + // execute the request + int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating node failed, no rows affected."); + } + Long uniqueSQLID = null; + // retreive uid inserted + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + uniqueSQLID = generatedKeys.getLong(1); + } else { + throw new SQLException("Creating node failed, no ID obtained (1)."); + } + } catch (Exception ex) { + System.out.println("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating node failed, no ID obtained (2)."); + } + if (primaryKeyField != null) { + if (primaryKeyField.getType() == Long.class) { + primaryKeyField.set(data, (Long)uniqueSQLID); + } else if (primaryKeyField.getType() == long.class) { + primaryKeyField.setLong(data, uniqueSQLID); + } else { + System.out.println("Can not manage the primary filed !!!"); + } + } + //ps.execute(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return data; + } + + public static T insertWithJson(Class clazz, String jsonData) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + T data = mapper.readValue(jsonData, clazz); + return insert(data); + } + + public static void update(Class clazz, long id, String jsonData) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + T data = mapper.readValue(jsonData, clazz); + // Read the tree to filter injection of data: + JsonNode root = mapper.readTree(jsonData); + List keys = new ArrayList<>(); + Iterator iterator = root.fieldNames(); + iterator.forEachRemaining(e -> keys.add(e)); + update(data, id, keys); + } + + public static void update(T data, long id, List filterValue) throws Exception { + Class clazz = data.getClass(); + //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("UPDATE "); + query.append(tableName); + query.append(" SET "); + + boolean firstField = true; + Field primaryKeyField = null; + int count = 0; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + primaryKeyField = elem; + continue; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (! updateTime && !filterValue.contains(name)) { + continue; + } + if (!elem.getClass().isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("` = "); + if (updateTime) { + query.append(" now(3) "); + } else { + query.append("? "); + } + } + query.append(" WHERE `"); + query.append(primaryKeyField.getName()); + query.append("` = ?"); + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + continue; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime || !filterValue.contains(name)) { + continue; + } + if (linkGeneric == ModelLink.NONE) { + Class type = elem.getType(); + if (!type.isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + setValuedb(type, data, iii++, elem, ps); + } else { + // transform the data in string to insert it ... + Object tmp = elem.get(data); + if (tmp == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + @SuppressWarnings("unchecked") + String dataTmp = getStringOfIds((List)tmp); + ps.setString(iii++, dataTmp); + } + } + count++; + } + ps.setLong(iii++, id); + // execute the request + int affectedRows = ps.executeUpdate(); + // todo manage the list of element is valid ... + //ps.execute(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + + public static T getWith(Class clazz, String key, String value) throws Exception { + //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + T out = null; + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("SELECT "); + //query.append(tableName); + //query.append(" SET "); + + boolean firstField = true; + Field primaryKeyField = null; + int count = 0; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + primaryKeyField = elem; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" "); + query.append(tableName); + query.append("."); + query.append(name); + } + query.append("\n FROM `"); + query.append(tableName); + query.append("` "); + query.append("\n WHERE "); + query.append(tableName); + query.append("."); + query.append(key); + query.append(" = ?"); + query.append("\n LIMIT 1 "); + /* + query.append(" AND "); + query.append(tableName); + query.append(".deleted = false "); + */ + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setString(iii++, value); + // execute the request + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (Field elem : clazz.getFields()) { + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + //this.name = rs.getString(iii++); + //this.description = rs.getString(iii++); + //this.covers = getListOfIds(rs, iii++); + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } + out = (T)data; + } + + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + entry = null; + return out; + } + + public static T getWhere(Class clazz, String key, String operator, Object value ) throws Exception { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + T out = null; + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("SELECT "); + //query.append(tableName); + //query.append(" SET "); + + boolean firstField = true; + int count = 0; + for (Field elem : clazz.getFields()) { + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" "); + query.append(tableName); + query.append("."); + + query.append(name); + } + query.append(" FROM `"); + query.append(tableName); + query.append("` "); + query.append(" WHERE "); + query.append(tableName); + query.append("."); + query.append(key); + query.append(" "); + query.append(operator); + query.append(" ?"); + /* + query.append(" AND "); + query.append(tableName); + query.append(".deleted = false "); + */ + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + if (value.getClass() == Long.class) { + ps.setLong(iii++, (Long)value); + } else if (value.getClass() == Integer.class) { + ps.setInt(iii++, (Integer)value); + } else if (value.getClass() == String.class) { + ps.setString(iii++, (String)value); + } else if (value.getClass() == Short.class) { + ps.setShort(iii++, (Short)value); + } else if (value.getClass() == Byte.class) { + ps.setByte(iii++, (Byte)value); + } else { + throw new Exception("Not manage type ==> need to add it ..."); + } + // execute the request + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (Field elem : clazz.getFields()) { + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + //this.name = rs.getString(iii++); + //this.description = rs.getString(iii++); + //this.covers = getListOfIds(rs, iii++); + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } + out = (T)data; + } + + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + entry = null; + return out; + } + + public static T get(Class clazz, long id) throws Exception { + Field primaryKeyField = null; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + primaryKeyField = elem; + } + } + if (primaryKeyField != null) { + return getWhere(clazz, primaryKeyField.getName(), "=", id); + } + throw new Exception("Missing primary Key..."); + } + + private enum StateLoad { + DISABLE, + NORMAL, + ARRAY + }; + + public static String getCurrentTimeStamp() { + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); + } + + public static List gets(Class clazz, boolean fool) throws Exception { + System.out.println("request get " + clazz.getCanonicalName() + " start @" + getCurrentTimeStamp()); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + List out = new ArrayList<>(); + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("SELECT "); + //query.append(tableName); + //query.append(" SET "); + + boolean firstField = true; + int count = 0; + StateLoad[] autoClasify = new StateLoad[clazz.getFields().length]; + int indexAutoClasify = 0; + for (Field elem : clazz.getFields()) { + + boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + if (!fool && notRead) { + autoClasify[indexAutoClasify++] = StateLoad.DISABLE; + continue; + } + String name = elem.getName(); + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + autoClasify[indexAutoClasify++] = StateLoad.ARRAY; + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length()-1); + } + String tmpVariable = "tmp_" + Integer.toString(count); + query.append(" (SELECT GROUP_CONCAT("); + query.append(tmpVariable); + query.append("."); + query.append(localName); + query.append("_id SEPARATOR '-') FROM "); + query.append(tableName); + query.append("_link_"); + query.append(localName); + query.append(" "); + query.append(tmpVariable); + query.append(" WHERE "); + query.append(tmpVariable); + query.append(".deleted = false AND "); + query.append(tableName); + query.append(".id = "); + query.append(tmpVariable); + query.append("."); + query.append(tableName); + query.append("_id GROUP BY "); + query.append(tmpVariable); + query.append("."); + query.append(tableName); + query.append("_id ) AS "); + query.append(name); + query.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" + + */ + } else { + if (linkGeneric == ModelLink.NONE) { + autoClasify[indexAutoClasify++] = StateLoad.NORMAL; + } else { + autoClasify[indexAutoClasify++] = StateLoad.ARRAY; + } + query.append(" "); + query.append(tableName); + query.append("."); + query.append(name); + } + } + query.append(" FROM `"); + query.append(tableName); + query.append("` "); + query.append(" WHERE "); + //query.append(tableName); + //query.append("."); + //query.append(primaryKeyField.getName()); + //query.append(" = ?"); + //query.append(" AND "); + query.append(tableName); + query.append(".deleted = false "); + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + System.out.println("request get " + clazz.getCanonicalName() + " prepare @" + getCurrentTimeStamp()); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + + System.out.println("request get " + clazz.getCanonicalName() + " query @" + getCurrentTimeStamp()); + // execute the request + ResultSet rs = ps.executeQuery(); + System.out.println("request get " + clazz.getCanonicalName() + " transform @" + getCurrentTimeStamp()); + + while (rs.next()) { + indexAutoClasify = 0; + Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (Field elem : clazz.getFields()) { + /* + boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + */ + boolean notRead = autoClasify[indexAutoClasify] == StateLoad.DISABLE; + if (!fool && notRead) { + indexAutoClasify++; + continue; + } + //String name = elem.getName(); + //boolean linkGeneric = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class).length != 0; + boolean linkGeneric = autoClasify[indexAutoClasify] == StateLoad.ARRAY; + if (linkGeneric) { + List idList = getListOfIds(rs, count); + elem.set(data, idList); + } else { + setValueFromDb(elem.getType(), data, count, elem, rs); + } + indexAutoClasify++; + count++; + } + //System.out.println("Read: " + (T)data); + out.add((T)data); + } + + System.out.println("request get " + clazz.getCanonicalName() + " ready @" + getCurrentTimeStamp()); + + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + entry = null; + return out; + } + + public static void addLink(Class clazz, long localKey, String table, long remoteKey) throws Exception { + String tableName = getTableName(clazz); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + long uniqueSQLID = -1; + // real add in the BDD: + try { + // prepare the request: + String query = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + + " VALUES (now(3), now(3), ?, ?)"; + PreparedStatement ps = entry.connection.prepareStatement(query, + Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setLong(iii++, localKey); + ps.setLong(iii++, remoteKey); + // execute the request + int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating data failed, no rows affected."); + } + // retreive 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 (Exception ex) { + System.out.println("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating user failed, no ID obtained (2)."); + } + } catch (SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.disconnect(); + } + } + public static void removeLink(Class clazz, long localKey, String table, long remoteKey) throws Exception { + String tableName = getTableName(clazz); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=now(3), `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table + "_id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + int iii = 1; + ps.setLong(iii++, localKey); + ps.setLong(iii++, remoteKey); + ps.executeUpdate(); + } catch (SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.disconnect(); + } + } + + /** + * 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 getListOfIds(ResultSet rs, int iii) throws SQLException { + String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + List out = new ArrayList<>(); + String[] elements = trackString.split("-"); + for (String elem : elements) { + Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + /** + * Convert the list if external Ids in a string '-' separated + * @param ids List of value (null are removed) + * @return '-' string separated + */ + protected static String getStringOfIds(List ids) { + List tmp = new ArrayList<>(); + for (Long elem : ids) { + tmp.add(elem); + } + return tmp.stream().map(x->String.valueOf(x)).collect(Collectors.joining("-")); + } + + + public static void delete(Class clazz, long id) throws Exception { + // TODO: I am not sure this is a real good idea. + } + public static void setDelete(Class clazz, long id) throws Exception { + String tableName = getTableName(clazz); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "UPDATE `" + tableName + "` SET `modify_date`=now(3), `deleted`=true WHERE `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + int iii = 1; + ps.setLong(iii++, id); + ps.executeUpdate(); + } catch (SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.disconnect(); + } + } + + public static String createTable(Class clazz) throws Exception { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder out = new StringBuilder(); + StringBuilder otherTable = new StringBuilder(); + // Drop Table + if (createIfNotExist) { + out.append("DROP TABLE IF EXISTS `"); + out.append(tableName); + out.append("`;\n"); + } + // create Table: + out.append("CREATE TABLE `"); + out.append(tableName); + out.append("` ("); + boolean firstField = true; + System.out.println("===> TABLE `" + tableName + "`"); + String primaryKeyValue = null; + for (Field elem : clazz.getFields()) { + + String name = elem.getName(); + Integer limitSize = getLimitSize(elem); + boolean notNull = elem.getDeclaredAnnotationsByType(SQLNotNull.class).length != 0; + boolean autoIncrement = elem.getDeclaredAnnotationsByType(SQLAutoIncrement.class).length != 0; + + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + //boolean sqlNotRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + ModelLink linkGeneric = getLinkMode(elem); + String comment = getComment(elem); + String defaultValue = getDefault(elem); + //System.out.println(" ==> elem `" + name + "` primaryKey=" + primaryKey + " linkGeneric=" + linkGeneric); + + + if (primaryKey) { + primaryKeyValue = name; + } + // special case with external link table: + if (linkGeneric == ModelLink.EXTERNAL) { + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length()-1); + } + if (createIfNotExist) { + otherTable.append("DROP TABLE IF EXISTS `"); + otherTable.append(tableName); + otherTable.append("_link_"); + otherTable.append(localName); + otherTable.append("`;\n"); + } + otherTable.append("CREATE TABLE `"); + otherTable.append(tableName); + otherTable.append("_link_"); + otherTable.append(localName); + otherTable.append("`(\n"); + 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"); + otherTable.append("\t\t`"); + otherTable.append(tableName); + otherTable.append("_id` bigint NOT NULL,\n"); + otherTable.append("\t\t`"); + otherTable.append(localName); + otherTable.append("_id` bigint NOT NULL,\n"); + otherTable.append("\tPRIMARY KEY (`id`)\n"); + otherTable.append("\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n"); + } else { + if (firstField) { + out.append("\n\t\t`"); + firstField = false; + } else { + out.append(",\n\t\t`"); + } + out.append(name); + out.append("` "); + String typeValue = null; + if (linkGeneric == ModelLink.INTERNAL) { + typeValue = convertTypeInSQL(String.class); + out.append(typeValue); + } else { + typeValue = convertTypeInSQL(elem.getType()); + if (typeValue.equals("text")) { + if (limitSize != null) { + out.append("varchar("); + out.append(limitSize); + out.append(")"); + } else { + out.append("text CHARACTER SET utf8"); + } + } else { + out.append(typeValue); + } + } + out.append(" "); + if (notNull) { + out.append("NOT NULL "); + if (defaultValue == null) { + if (updateTime || createTime) { + out.append("DEFAULT CURRENT_TIMESTAMP(3) "); + } + } else { + out.append("DEFAULT "); + out.append(defaultValue); + out.append(" "); + } + } else if (defaultValue == null) { + if (updateTime || createTime) { + out.append("DEFAULT CURRENT_TIMESTAMP(3) "); + } else { + out.append("DEFAULT NULL "); + } + } else { + out.append("DEFAULT "); + out.append(defaultValue); + out.append(" "); + + } + if (autoIncrement) { + out.append("AUTO_INCREMENT "); + } + + if (comment != null) { + out.append("COMMENT '"); + out.append(comment.replaceAll("'", "\'")); + out.append("' "); + } + } + } + if (primaryKeyValue != null) { + out.append(",\n\tPRIMARY KEY (`"); + out.append(primaryKeyValue); + out.append("`)"); + } + out.append("\n\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n"); + return out.toString() + otherTable.toString(); + } + + + public static String getTableName(final Class element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLTableName.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); + } + final String tmp = ((SQLTableName) annotation[0]).value(); + 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 @AknotDescription 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 @AknotDescription 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(SQLLimitSize.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); + } + return ((SQLLimitSize) annotation[0]).value(); + } + +} \ No newline at end of file diff --git a/src/org/kar/archidata/UpdateJwtPublicKey.java b/src/org/kar/archidata/UpdateJwtPublicKey.java new file mode 100644 index 0000000..a8e0594 --- /dev/null +++ b/src/org/kar/archidata/UpdateJwtPublicKey.java @@ -0,0 +1,34 @@ +package org.kar.archidata; + +import org.kar.archidata.util.ConfigBaseVariable; +import org.kar.archidata.util.JWTWrapper; + +public class UpdateJwtPublicKey extends Thread { + boolean kill = false; + public void run() { + try { + Thread.sleep(1000*20, 0); + } catch (InterruptedException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } + while (this.kill == false) { + // need to uppgrade when server call us... + try { + JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata"); + } catch (Exception e1) { + e1.printStackTrace(); + System.out.println("Can not retreive the basic tocken"); + return; + } + try { + Thread.sleep(1000*60*5, 0); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + public void kill() { + this.kill = true; + } +} \ No newline at end of file diff --git a/src/org/kar/archidata/UserDB.java b/src/org/kar/archidata/UserDB.java new file mode 100755 index 0000000..d638e1e --- /dev/null +++ b/src/org/kar/archidata/UserDB.java @@ -0,0 +1,133 @@ +package org.kar.archidata; + +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.model.User; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class UserDB { + + public UserDB() { + } + + public static User getUsers(long userId) throws Exception { + return SqlWrapper.get(User.class, userId); + /* + DBEntry entry = new DBEntry(WebLauncher.dbConfig); + String query = "SELECT * FROM user WHERE id = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, userId); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + User out = new User(rs); + entry.disconnect(); + return out; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + return null; + */ + } + + + public static User getUserOrCreate(long userId, String userLogin) throws Exception { + User user = getUsers(userId); + if (user != null) { + /* + boolean blocked = false; + boolean removed = false; + if (user.email != userOAuth.email || user.login != userOAuth.login || user.blocked != blocked || user.removed != removed) { + updateUsersInfoFromOAuth(userOAuth.id, userOAuth.email, userOAuth.login, blocked, removed); + } else { + updateUsersConnectionTime(userOAuth.id); + } + return getUsers(userOAuth.id); + */ + return user; + } + createUsersInfoFromOAuth(userId, userLogin); + return getUsers(userId); + } +/* + private static void updateUsersConnectionTime(long userId) { + DBEntry entry = new DBEntry(WebLauncher.dbConfig); + String query = "UPDATE `user` SET `lastConnection`=now(3) WHERE `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, userId); + ps.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + + private static void updateUsersInfoFromOAuth(long userId, String email, String login, boolean blocked, boolean removed) { + DBEntry entry = new DBEntry(WebLauncher.dbConfig); + String query = "UPDATE `user` SET `login`=?, `email`=?, `lastConnection`=now(3), `blocked`=?, `removed`=? WHERE id = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setString(1, login); + ps.setString(2, email); + ps.setString(3, blocked ? "TRUE" : "FALSE"); + ps.setString(4, removed ? "TRUE" : "FALSE"); + ps.setLong(5, userId); + ps.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + */ + + private static void createUsersInfoFromOAuth(long userId, String login) { + DBEntry entry = new DBEntry(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(); + } + entry.disconnect(); + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/kar/archidata/annotation/PermitTokenInURI.java b/src/org/kar/archidata/annotation/PermitTokenInURI.java new file mode 100644 index 0000000..95a1117 --- /dev/null +++ b/src/org/kar/archidata/annotation/PermitTokenInURI.java @@ -0,0 +1,15 @@ +package org.kar.archidata.annotation; + +import javax.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.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@NameBinding +@Retention(RUNTIME) +@Target({METHOD}) +public @interface PermitTokenInURI { +} diff --git a/src/org/kar/archidata/annotation/SQLAutoIncrement.java b/src/org/kar/archidata/annotation/SQLAutoIncrement.java new file mode 100644 index 0000000..8c22c7d --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLAutoIncrement.java @@ -0,0 +1,12 @@ +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 SQLAutoIncrement { + +} diff --git a/src/org/kar/archidata/annotation/SQLComment.java b/src/org/kar/archidata/annotation/SQLComment.java new file mode 100644 index 0000000..9bfa21f --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLComment.java @@ -0,0 +1,14 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLComment { + + String value(); + +} diff --git a/src/org/kar/archidata/annotation/SQLCreateTime.java b/src/org/kar/archidata/annotation/SQLCreateTime.java new file mode 100644 index 0000000..51dfdec --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLCreateTime.java @@ -0,0 +1,12 @@ +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 SQLCreateTime { + +} diff --git a/src/org/kar/archidata/annotation/SQLDefault.java b/src/org/kar/archidata/annotation/SQLDefault.java new file mode 100644 index 0000000..ec88f2e --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLDefault.java @@ -0,0 +1,14 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLDefault { + + String value(); + +} diff --git a/src/org/kar/archidata/annotation/SQLIfNotExists.java b/src/org/kar/archidata/annotation/SQLIfNotExists.java new file mode 100644 index 0000000..9b185d6 --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLIfNotExists.java @@ -0,0 +1,12 @@ +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 SQLIfNotExists { + +} diff --git a/src/org/kar/archidata/annotation/SQLLimitSize.java b/src/org/kar/archidata/annotation/SQLLimitSize.java new file mode 100644 index 0000000..5ed10c4 --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLLimitSize.java @@ -0,0 +1,12 @@ +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(); +} diff --git a/src/org/kar/archidata/annotation/SQLNotNull.java b/src/org/kar/archidata/annotation/SQLNotNull.java new file mode 100644 index 0000000..07a20aa --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLNotNull.java @@ -0,0 +1,12 @@ +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 SQLNotNull { + +} diff --git a/src/org/kar/archidata/annotation/SQLNotRead.java b/src/org/kar/archidata/annotation/SQLNotRead.java new file mode 100644 index 0000000..50bb67b --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLNotRead.java @@ -0,0 +1,12 @@ +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 SQLNotRead { + +} diff --git a/src/org/kar/archidata/annotation/SQLPrimaryKey.java b/src/org/kar/archidata/annotation/SQLPrimaryKey.java new file mode 100644 index 0000000..60944cf --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLPrimaryKey.java @@ -0,0 +1,12 @@ +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 SQLPrimaryKey { + +} diff --git a/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java b/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java new file mode 100644 index 0000000..b8f9632 --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java @@ -0,0 +1,20 @@ +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 SQLTableLinkGeneric { + public enum ModelLink { + NONE, + INTERNAL, + EXTERNAL + }; + ModelLink value() default ModelLink.EXTERNAL; +} diff --git a/src/org/kar/archidata/annotation/SQLTableName.java b/src/org/kar/archidata/annotation/SQLTableName.java new file mode 100644 index 0000000..5902edc --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLTableName.java @@ -0,0 +1,14 @@ +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(); + +} diff --git a/src/org/kar/archidata/annotation/SQLUpdateTime.java b/src/org/kar/archidata/annotation/SQLUpdateTime.java new file mode 100644 index 0000000..fe2ecad --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLUpdateTime.java @@ -0,0 +1,12 @@ +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 { + +} diff --git a/src/org/kar/archidata/api/FrontGeneric.java b/src/org/kar/archidata/api/FrontGeneric.java new file mode 100644 index 0000000..7f699af --- /dev/null +++ b/src/org/kar/archidata/api/FrontGeneric.java @@ -0,0 +1,104 @@ +package org.kar.archidata.api; + +import java.io.File; +import java.util.List; + +import javax.annotation.security.PermitAll; +import javax.ws.rs.*; +import javax.ws.rs.core.CacheControl; +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + + +public class FrontGeneric { + + protected String baseFrontFolder = "/data/front"; + + private String getExtension(String filename) { + 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; + System.out.println("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 { + return Response.status(403). + entity("Not supported model: '" + fileName + "'"). + type("text/plain"). + build(); + } + } else { + mineType = "text/html"; + filePathName = baseFrontFolder + File.separator + "index.html"; + } + System.out.println(" ==> '" + filePathName + "'"); + // reads input image + File download = new File(filePathName); + if (!download.exists()) { + return Response.status(404). + entity("Not Found: '" + fileName + "' extension='" + extention + "'"). + type("text/plain"). + build(); + } + 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 segments) throws Exception { + String filename = ""; + for (PathSegment elem: segments) { + if (!filename.isEmpty()) { + filename += File.separator; + } + filename += elem.getPath(); + } + return retrive(filename); + } +} diff --git a/src/org/kar/archidata/db/DBConfig.java b/src/org/kar/archidata/db/DBConfig.java new file mode 100644 index 0000000..577a658 --- /dev/null +++ b/src/org/kar/archidata/db/DBConfig.java @@ -0,0 +1,60 @@ +package org.kar.archidata.db; + +public class DBConfig { + private final String hostname; + private final int port; + private final String login; + private final String password; + private final String dbName; + + public DBConfig(String hostname, Integer port, String login, String password, String dbName) { + 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; + } + + @Override + public String toString() { + return "DBConfig{" + + "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 String getUrl() { + return "jdbc:mysql://" + this.hostname + ":" + this.port + "/" + this.dbName + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; + } +} diff --git a/src/org/kar/archidata/db/DBEntry.java b/src/org/kar/archidata/db/DBEntry.java new file mode 100644 index 0000000..32c9f05 --- /dev/null +++ b/src/org/kar/archidata/db/DBEntry.java @@ -0,0 +1,45 @@ +package org.kar.archidata.db; + +import org.kar.archidata.model.User; + +import java.sql.*; + +public class DBEntry { + public DBConfig config; + public Connection connection; + + public DBEntry(DBConfig config) { + this.config = config; + connect(); + } + + public void connect() { + try { + connection = DriverManager.getConnection(config.getUrl(), config.getLogin(), config.getPassword()); + } catch (SQLException ex) { + ex.printStackTrace(); + } + + } + + public void disconnect() { + try { + //connection.commit(); + connection.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } +/* + public void test() throws SQLException { + String query = "SELECT * FROM user"; + Statement st = connection.createStatement(); + ResultSet rs = st.executeQuery(query); + System.out.println("List of user:"); + if (rs.next()) { + User user = new User(rs); + System.out.println(" - " + user); + } + } + */ +} diff --git a/src/org/kar/archidata/filter/AuthenticationFilter.java b/src/org/kar/archidata/filter/AuthenticationFilter.java new file mode 100644 index 0000000..7a93842 --- /dev/null +++ b/src/org/kar/archidata/filter/AuthenticationFilter.java @@ -0,0 +1,198 @@ +package org.kar.archidata.filter; + +import java.lang.reflect.Method; +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + + +import javax.annotation.Priority; +import javax.ws.rs.Priorities; +import javax.ws.rs.QueryParam; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +import org.kar.archidata.UserDB; +import org.kar.archidata.annotation.PermitTokenInURI; +import org.kar.archidata.model.User; +import org.kar.archidata.model.UserSmall; +import org.kar.archidata.util.JWTWrapper; + +import com.nimbusds.jwt.JWTClaimsSet; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +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) +public class AuthenticationFilter implements ContainerRequestFilter { + @Context + private ResourceInfo resourceInfo; + + private static final String AUTHENTICATION_SCHEME = "Yota"; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + /* + System.out.println("-----------------------------------------------------"); + System.out.println("---- Check if have authorization ----"); + System.out.println("-----------------------------------------------------"); + System.out.println(" for:" + requestContext.getUriInfo().getPath()); + */ + Method method = resourceInfo.getResourceMethod(); + // Access denied for all + if(method.isAnnotationPresent(DenyAll.class)) { + System.out.println(" ==> 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)) { + System.out.println(" ==> 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)) { + System.out.println(" ==> missin @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); + //System.out.println("authorizationHeader: " + authorizationHeader); + if(authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) { + MultivaluedMap quaryparam = requestContext.getUriInfo().getQueryParameters(); + for (Entry> item: quaryparam.entrySet()) { + if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) { + if (!item.getValue().isEmpty()) { + authorizationHeader = item.getValue().get(0); + } + break; + } + } + } + //System.out.println("authorizationHeader: " + authorizationHeader); + + + /* + System.out.println(" -------------------------------"); + // this get the parameters inside the pre-parsed element in the request ex: @Path("thumbnail/{id}") generate a map with "id" + MultivaluedMap pathparam = requestContext.getUriInfo().getPathParameters(); + for (Entry> item: pathparam.entrySet()) { + System.out.println(" param: " + item.getKey() + " ==>" + item.getValue()); + } + System.out.println(" -------------------------------"); + // need to add "@QueryParam("p") String token, " in the model + //MultivaluedMap quaryparam = requestContext.getUriInfo().getQueryParameters(); + for (Entry> item: quaryparam.entrySet()) { + System.out.println(" query: " + item.getKey() + " ==>" + item.getValue()); + } + System.out.println(" -------------------------------"); + List segments = requestContext.getUriInfo().getPathSegments(); + for (final PathSegment item: segments) { + System.out.println(" query: " + item.getPath() + " ==>" + item.getMatrixParameters()); + } + System.out.println(" -------------------------------"); + MultivaluedMap headers = requestContext.getHeaders(); + for (Entry> item: headers.entrySet()) { + System.out.println(" headers: " + item.getKey() + " ==>" + item.getValue()); + } + System.out.println(" -------------------------------"); + */ + // Validate the Authorization header data Model "Yota userId:token" + if (!isTokenBasedAuthentication(authorizationHeader)) { + System.out.println("REJECTED unauthorized: " + requestContext.getUriInfo().getPath()); + abortWithUnauthorized(requestContext); + return; + } + // check JWT token (basic:) + + // Extract the token from the Authorization header (Remove "Yota ") + String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim(); + System.out.println("token: " + token); + + + User user = null; + try { + user = validateToken(token); + } catch (Exception e) { + abortWithUnauthorized(requestContext); + } + if (user == null) { + abortWithUnauthorized(requestContext); + } + // create the security context model: + String scheme = requestContext.getUriInfo().getRequestUri().getScheme(); + MySecurityContext userContext = new MySecurityContext(user, scheme); + // retrieve the allowed right: + RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); + List 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) { + System.out.println("REJECTED not enought right : " + requestContext.getUriInfo().getPath() + " require: " + roles); + requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build()); + return; + } + requestContext.setSecurityContext(userContext); + System.out.println("Get local user : " + user); + } + + 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 void abortWithUnauthorized(ContainerRequestContext requestContext) { + + // Abort the filter chain with a 401 status code response + // The WWW-Authenticate header is sent along with the response + requestContext.abortWith( + Response.status(Response.Status.UNAUTHORIZED) + .header(HttpHeaders.WWW_AUTHENTICATE, + AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)") + .build()); + } + + private User validateToken(String authorization) throws Exception { + System.out.println(" validate token : " + authorization); + JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth"); + // check the token is valid !!! (signed and coherent issuer... + if (ret == null) { + System.out.println("The token is not valid: '" + authorization + "'"); + return null; + } + // check userID + String userUID = ret.getSubject(); + long id = Long.parseLong(userUID); + System.out.println("request user: '" + userUID + "'"); + return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") ); + } +} diff --git a/src/org/kar/archidata/filter/CORSFilter.java b/src/org/kar/archidata/filter/CORSFilter.java new file mode 100644 index 0000000..ce7f798 --- /dev/null +++ b/src/org/kar/archidata/filter/CORSFilter.java @@ -0,0 +1,25 @@ +package org.kar.archidata.filter; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.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"); + } +} diff --git a/src/org/kar/archidata/filter/GenericContext.java b/src/org/kar/archidata/filter/GenericContext.java new file mode 100644 index 0000000..faeb5c9 --- /dev/null +++ b/src/org/kar/archidata/filter/GenericContext.java @@ -0,0 +1,22 @@ +package org.kar.archidata.filter; + +import org.kar.archidata.model.User; + +import java.security.Principal; + +public class GenericContext implements Principal { + + public User user; + + public GenericContext(User user) { + this.user = user; + } + + @Override + public String getName() { + if (user == null) { + return "???"; + } + return user.login; + } +} diff --git a/src/org/kar/archidata/filter/MySecurityContext.java b/src/org/kar/archidata/filter/MySecurityContext.java new file mode 100644 index 0000000..b61a564 --- /dev/null +++ b/src/org/kar/archidata/filter/MySecurityContext.java @@ -0,0 +1,47 @@ +package org.kar.archidata.filter; + + +import org.kar.archidata.model.User; + +import javax.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(User user, String sheme) { + this.contextPrincipale = new GenericContext(user); + this.sheme = sheme; + } + + @Override + public Principal getUserPrincipal() { + return contextPrincipale; + } + + @Override + public boolean isUserInRole(String role) { + if (role.contentEquals("ADMIN")) { + return contextPrincipale.user.admin == true; + } + if (role.contentEquals("USER")) { + // if not an admin, this is a user... + return true; //contextPrincipale.user.admin == false; + } + return false; + } + + @Override + public boolean isSecure() { + return true; + } + + @Override + public String getAuthenticationScheme() { + return "Yota"; + } + +} \ No newline at end of file diff --git a/src/org/kar/archidata/filter/OptionFilter.java b/src/org/kar/archidata/filter/OptionFilter.java new file mode 100644 index 0000000..bfe9527 --- /dev/null +++ b/src/org/kar/archidata/filter/OptionFilter.java @@ -0,0 +1,21 @@ +package org.kar.archidata.filter; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Response; +import javax.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()); + } + } +} + + diff --git a/src/org/kar/archidata/internal/Log.java b/src/org/kar/archidata/internal/Log.java new file mode 100644 index 0000000..d8545ff --- /dev/null +++ b/src/org/kar/archidata/internal/Log.java @@ -0,0 +1,60 @@ +package org.kar.archidata.internal; + +//import io.scenarium.logger.LogLevel; +//import io.scenarium.logger.Logger; + +public class Log { +// private static final String LIB_NAME = "logger"; +// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); +// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); +// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); +// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); +// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); +// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); +// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); +// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); +// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); +// +// private Log() {} +// +// public static void print(String data) { +// if (PRINT_PRINT) +// Logger.print(LIB_NAME_DRAW, data); +// } +// +// public static void todo(String data) { +// if (PRINT_TODO) +// Logger.todo(LIB_NAME_DRAW, data); +// } +// +// public static void critical(String data) { +// if (PRINT_CRITICAL) +// Logger.critical(LIB_NAME_DRAW, data); +// } +// +// public static void error(String data) { +// if (PRINT_ERROR) +// Logger.error(LIB_NAME_DRAW, data); +// } +// +// public static void warning(String data) { +// if (PRINT_WARNING) +// Logger.warning(LIB_NAME_DRAW, data); +// } +// +// public static void info(String data) { +// if (PRINT_INFO) +// Logger.info(LIB_NAME_DRAW, data); +// } +// +// public static void debug(String data) { +// if (PRINT_DEBUG) +// Logger.debug(LIB_NAME_DRAW, data); +// } +// +// public static void verbose(String data) { +// if (PRINT_VERBOSE) +// Logger.verbose(LIB_NAME_DRAW, data); +// } + +} diff --git a/src/org/kar/archidata/model/Data.java b/src/org/kar/archidata/model/Data.java new file mode 100644 index 0000000..a34617a --- /dev/null +++ b/src/org/kar/archidata/model/Data.java @@ -0,0 +1,32 @@ +package org.kar.archidata.model; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Data { + public Long id; + public boolean deleted; + public String sha512; + public String mimeType; + public Long size; + + public Data() { + + } + + public Data(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.deleted = rs.getBoolean(iii++); + this.sha512 = rs.getString(iii++); + this.mimeType = rs.getString(iii++); + this.size = rs.getLong(iii++); + if (rs.wasNull()) { + this.size = null; + } + } catch (SQLException ex) { + ex.printStackTrace(); + } + } +} diff --git a/src/org/kar/archidata/model/GenericTable.java b/src/org/kar/archidata/model/GenericTable.java new file mode 100644 index 0000000..8134c8e --- /dev/null +++ b/src/org/kar/archidata/model/GenericTable.java @@ -0,0 +1,35 @@ +package org.kar.archidata.model; + +import java.sql.Timestamp; + +import org.kar.archidata.annotation.SQLAutoIncrement; +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLCreateTime; +import org.kar.archidata.annotation.SQLDefault; +import org.kar.archidata.annotation.SQLNotNull; +import org.kar.archidata.annotation.SQLNotRead; +import org.kar.archidata.annotation.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLUpdateTime; + +public class GenericTable { + @SQLAutoIncrement // Add AUTO_INCREMENT modifier + @SQLPrimaryKey // Create a PRIMARY KEY based on this field + @SQLNotNull + @SQLComment("Primary key of the base") + public Long id = null; + @SQLNotRead + @SQLNotNull + @SQLDefault("'0'") + @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") + public Timestamp create_date = null; + @SQLNotRead + @SQLUpdateTime + @SQLNotNull + @SQLComment("When update the object") + public Timestamp modify_date = null; +} diff --git a/src/org/kar/archidata/model/State.java b/src/org/kar/archidata/model/State.java new file mode 100644 index 0000000..bd3195e --- /dev/null +++ b/src/org/kar/archidata/model/State.java @@ -0,0 +1,12 @@ +package org.kar.archidata.model; + +public enum State { + // User has remove his account + REMOVED, + // User has been blocked his account + BLOCKED, + // generic user + USER, + // Administrator + ADMIN +} diff --git a/src/org/kar/archidata/model/Token.java b/src/org/kar/archidata/model/Token.java new file mode 100644 index 0000000..636cbfd --- /dev/null +++ b/src/org/kar/archidata/model/Token.java @@ -0,0 +1,57 @@ +package org.kar.archidata.model; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/* +CREATE TABLE `token` ( + `id` bigint NOT NULL COMMENT 'Unique ID of the TOKEN' AUTO_INCREMENT PRIMARY KEY, + `userId` bigint NOT NULL COMMENT 'Unique ID of the user', + `token` varchar(128) COLLATE 'latin1_bin' NOT NULL COMMENT 'Token (can be not unique)', + `createTime` datetime NOT NULL COMMENT 'Time the token has been created', + `endValidityTime` datetime NOT NULL COMMENT 'Time of the token end validity' +) AUTO_INCREMENT=10; + + */ +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 + + '}'; + } +} diff --git a/src/org/kar/archidata/model/User.java b/src/org/kar/archidata/model/User.java new file mode 100644 index 0000000..9fbf596 --- /dev/null +++ b/src/org/kar/archidata/model/User.java @@ -0,0 +1,53 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `lastConnection` datetime NOT NULL COMMENT 'last connection time', + `admin` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `blocked` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `removed` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `avatar` bigint DEFAULT NULL, +) AUTO_INCREMENT=10; + + */ + +import java.sql.Timestamp; + +import org.kar.archidata.annotation.SQLAutoIncrement; +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.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLTableName; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@SQLTableName ("user") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class User { + @SQLAutoIncrement // Add AUTO_INCREMENT modifier + @SQLPrimaryKey // Create a PRIMARY KEY based on this field + @SQLNotNull + @SQLComment("Primary key of the base") + public Long id = null; + @SQLLimitSize(256) + 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; + +} diff --git a/src/org/kar/archidata/model/UserExtern.java b/src/org/kar/archidata/model/UserExtern.java new file mode 100644 index 0000000..2a1b61c --- /dev/null +++ b/src/org/kar/archidata/model/UserExtern.java @@ -0,0 +1,36 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `lastConnection` datetime NOT NULL COMMENT 'last connection time', + `admin` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `blocked` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `removed` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE' +) AUTO_INCREMENT=10; + + */ + + +public class UserExtern { + public Long id; + public String login; + public boolean admin; + + public UserExtern(User other) { + this.id = other.id; + this.login = other.login; + this.admin = other.admin; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", login='" + login + '\'' + + ", admin=" + admin + + '}'; + } +} diff --git a/src/org/kar/archidata/model/UserPerso.java b/src/org/kar/archidata/model/UserPerso.java new file mode 100644 index 0000000..8c1be5b --- /dev/null +++ b/src/org/kar/archidata/model/UserPerso.java @@ -0,0 +1,42 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `lastConnection` datetime NOT NULL COMMENT 'last connection time', + `admin` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `blocked` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `removed` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE' +) AUTO_INCREMENT=10; + + */ + + +public class UserPerso { + public Long id; + public String login; + public boolean admin; + public boolean blocked; + public boolean removed; + + public UserPerso(User other) { + this.id = other.id; + this.login = other.login; + this.admin = other.admin; + this.blocked = other.blocked; + this.removed = other.removed; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", login='" + login + '\'' + + ", admin=" + admin + + ", blocked=" + blocked + + ", removed=" + removed + + '}'; + } +} diff --git a/src/org/kar/archidata/model/UserSmall.java b/src/org/kar/archidata/model/UserSmall.java new file mode 100644 index 0000000..91cb8e8 --- /dev/null +++ b/src/org/kar/archidata/model/UserSmall.java @@ -0,0 +1,73 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `password` varchar(128) COLLATE 'latin1_bin' NOT NULL COMMENT 'password of the user hashed (sha512)', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `emailValidate` bigint COMMENT 'date of the email validation', + `newEmail` varchar(512) COLLATE 'utf8_general_ci' COMMENT 'email of the user if he want to change', + `authorisationLevel` enum("REMOVED", "USER", "ADMIN") NOT NULL COMMENT 'user level of authorization' +) AUTO_INCREMENT=10; + + */ + + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class UserSmall { + public long id; + public String login; + public String email; + public State authorisationLevel; + + public UserSmall() { + } + + public UserSmall(long id, String login, String email, State authorisationLevel) { + this.id = id; + this.login = login; + this.email = email; + this.authorisationLevel = authorisationLevel; + } + + public UserSmall(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.login = rs.getString(iii++); + this.email = rs.getString(iii++); + this.authorisationLevel = State.valueOf(rs.getString(iii++)); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + /* + public void serialize(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.login = rs.getString(iii++); + this.password = rs.getString(iii++); + this.email = rs.getString(iii++); + this.emailValidate = rs.getLong(iii++); + this.newEmail = rs.getString(iii++); + this.authorisationLevel = State.valueOf(rs.getString(iii++)); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + */ + + @Override + public String toString() { + return "UserSmall{" + + "id='" + id + '\'' + + ", login='" + login + '\'' + + ", email='" + email + '\'' + + ", authorisationLevel=" + authorisationLevel + + '}'; + } +} diff --git a/src/org/kar/archidata/util/ConfigBaseVariable.java b/src/org/kar/archidata/util/ConfigBaseVariable.java new file mode 100644 index 0000000..c0ad146 --- /dev/null +++ b/src/org/kar/archidata/util/ConfigBaseVariable.java @@ -0,0 +1,78 @@ +package org.kar.archidata.util; + +public class ConfigBaseVariable { + + public static String getTmpDataFolder() { + String out = System.getenv("DATA_TMP_FOLDER"); + if (out == null) { + return "/application/data/tmp"; + } + return out; + } + + public static String getMediaDataFolder() { + String out = System.getenv("DATA_FOLDER"); + if (out == null) { + return "/application/data/media"; + } + return out; + } + + public static String getDBHost() { + String out = System.getenv("DB_HOST"); + if (out == null) { + return "localhost"; + } + return out; + } + + public static String getDBPort() { + String out = System.getenv("DB_PORT"); + if (out == null) { + return "80"; + //return "17036"; + } + return out; + } + + public static String getDBLogin() { + String out = System.getenv("DB_USER"); + if (out == null) { + return "root"; + } + return out; + } + + public static String getDBPassword() { + String out = System.getenv("DB_PASSWORD"); + if (out == null) { + return "archidata_password"; + } + return out; + } + + public static String getDBName() { + String out = System.getenv("DB_DATABASE"); + if (out == null) { + return "unknown"; + } + return out; + } + + public static String getlocalAddress() { + String out = System.getenv("API_ADDRESS"); + if (out == null) { + return "http://0.0.0.0:80/api/"; + } + return out; + } + + public static String getSSOAddress() { + String out = System.getenv("SSO_ADDRESS"); + if (out == null) { + return "http://sso_host/karauth/api/"; + //return "http://192.168.1.156/karauth/api/"; + } + return out; + } +} diff --git a/src/org/kar/archidata/util/DataTools.java b/src/org/kar/archidata/util/DataTools.java new file mode 100644 index 0000000..431fc9a --- /dev/null +++ b/src/org/kar/archidata/util/DataTools.java @@ -0,0 +1,346 @@ +package org.kar.archidata.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +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.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.SqlWrapper; +import org.kar.archidata.model.Data; +import org.kar.archidata.db.DBEntry; + +public class DataTools { + + 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))) { + System.out.println("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) { + System.out.println("find sha512 = " + sha512); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "SELECT `id`, `deleted`, `sha512`, `mime_type`, `size` FROM `data` WHERE `sha512` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setString(1, sha512); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + Data out = new Data(rs); + entry.disconnect(); + return out; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + return null; + + } + + public static Data getWithId(long id) { + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "SELECT `id`, `deleted`, `sha512`, `mime_type`, `size` FROM `data` WHERE `deleted` = false AND `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, id); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + Data out = new Data(rs); + entry.disconnect(); + return out; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + 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)); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + long uniqueSQLID = -1; + try { + // prepare the request: + String query = "INSERT INTO `data` (`sha512`, `mime_type`, `size`, `original_name`) VALUES (?, ?, ?, ?)"; + PreparedStatement ps = entry.connection.prepareStatement(query, + Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setString(iii++, sha512); + ps.setString(iii++, mimeType); + ps.setLong(iii++, fileSize); + ps.setString(iii++, originalFileName); + // execute the request + int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating data failed, no rows affected."); + } + // retreive 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 (Exception ex) { + System.out.println("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating user failed, no ID obtained (2)."); + } + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + System.out.println("Add Data raw done. uid data=" + uniqueSQLID); + Data out = getWithId(uniqueSQLID); + + String mediaPath = getFileData(out.id); + System.out.println("src = " + tmpPath); + System.out.println("dst = " + mediaPath); + Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); + + System.out.println("Move done"); + // all is done the file is corectly installed... + + return out; + } + + public static void undelete(Long id) { + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "UPDATE `data` SET `deleted` = false WHERE `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, id); + ps.execute(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + + 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) { + System.out.println("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) { + //System.out.println("write " + read); + md.update(bytes, 0, read); + outpuStream.write(bytes, 0, read); + } + System.out.println("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) { + System.out.println("Can not write in temporary file ... "); + ex.printStackTrace(); + } catch (NoSuchAlgorithmException ex) { + System.out.println("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 Response uploadCover(Class clazz, + Long id, + String fileName, + InputStream fileInputStream, + FormDataContentDisposition fileMetaData + ) { + try { + // correct input string stream : + fileName = multipartCorrection(fileName); + + //public NodeSmall uploadFile(final FormDataMultiPart form) { + System.out.println("Upload media file: " + fileMetaData); + System.out.println(" - id: " + id); + System.out.println(" - file_name: " + fileName); + System.out.println(" - fileInputStream: " + fileInputStream); + System.out.println(" - fileMetaData: " + fileMetaData); + System.out.flush(); + 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) { + System.out.println("Need to add the data in the BDD ... "); + System.out.flush(); + 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) { + System.out.println("Data already exist but deleted"); + System.out.flush(); + undelete(data.id); + data.deleted = false; + } else { + System.out.println("Data already exist ... all good"); + System.out.flush(); + } + // Fist step: retrieve all the Id of each parents:... + System.out.println("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(); + } +} diff --git a/src/org/kar/archidata/util/JWTWrapper.java b/src/org/kar/archidata/util/JWTWrapper.java new file mode 100644 index 0000000..85aeac0 --- /dev/null +++ b/src/org/kar/archidata/util/JWTWrapper.java @@ -0,0 +1,175 @@ +package org.kar.archidata.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.ParseException; +import java.util.Date; +import java.util.UUID; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JOSEObjectType; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +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 static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException { + // check Token: + URL obj = new URL(ssoUri + "public_key"); + System.out.println("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"); + int responseCode = con.getResponseCode(); + + System.out.println("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 + //System.out.println(response.toString()); + ObjectMapper mapper = new ObjectMapper(); + PublicKey values = mapper.readValue(response.toString(), PublicKey.class); + rsaPublicJWK = RSAKey.parse(values.key); + return; + } + System.out.println("GET JWT validator token not worked"); + } + + public static void initLocalToken() 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 { + String generatedStringForKey = UUID.randomUUID().toString(); + rsaJWK = new RSAKeyGenerator(2048).keyID(generatedStringForKey).generate(); + rsaPublicJWK = rsaJWK.toPublicJWK(); + //System.out.println("RSA key (all): " + rsaJWK.toJSONString()); + //System.out.println("RSA key (pub): " + rsaPublicJWK.toJSONString()); + } catch (JOSEException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.out.println("Can not generate teh public abnd private keys ..."); + rsaJWK = null; + rsaPublicJWK = null; + } + } + + public static void initValidateToken(String publicKey) { + try { + rsaPublicJWK = RSAKey.parse(publicKey); + } catch (ParseException e) { + e.printStackTrace(); + System.out.println("Can not retrieve public Key !!!!!!!! RSAKey='" + publicKey + "'"); + } + + } + public static String getPublicKey() { + if (rsaPublicJWK == null) { + return null; + } + return rsaPublicJWK.toJSONString(); + } + + /** + * Create a token with the provided elements + * @param userID UniqueId of the USER (global unique ID) + * @param userLogin Login of the user (never change) + * @param isuer The one who provide the Token + * @param timeOutInMunites Expiration of the token. + * @return the encoded token + */ + public static String generateJWToken(long userID, String userLogin, String isuer, int timeOutInMunites) { + if (rsaJWK == null) { + System.out.println("JWT private key is not present !!!"); + return null; + } + try { + // Create RSA-signer with the private key + JWSSigner signer = new RSASSASigner(rsaJWK); + // Prepare JWT with claims set + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject(Long.toString(userID)) + .claim("login", userLogin) + .issuer(isuer) + .issueTime(new Date()) + .expirationTime(new Date(new Date().getTime() + 60 * timeOutInMunites * 1000 /* millisecond */)) + .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... + return signedJWT.serialize(); + } catch (JOSEException ex) { + ex.printStackTrace(); + } + return null; + } + + public static JWTClaimsSet validateToken(String signedToken, String isuer) { + if (rsaPublicJWK == null) { + System.out.println("JWT public key is not present !!!"); + return null; + } + 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)) { + System.out.println("JWT token is NOT verified "); + return null; + } + if (!new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime())) { + System.out.println("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime() ); + return null; + } + if (!isuer.equals(signedJWT.getJWTClaimsSet().getIssuer())) { + System.out.println("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'" ); + return null; + } + // the element must be validated outside ... + //System.out.println("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'"); + //System.out.println("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'"); + return signedJWT.getJWTClaimsSet(); + } catch (JOSEException ex) { + ex.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/org/kar/archidata/util/PublicKey.java b/src/org/kar/archidata/util/PublicKey.java new file mode 100644 index 0000000..f6968be --- /dev/null +++ b/src/org/kar/archidata/util/PublicKey.java @@ -0,0 +1,10 @@ +package org.kar.archidata.util; + + +public class PublicKey { + public String key; + + public PublicKey(String key) { + this.key = key; + } +} \ No newline at end of file