diff --git a/README.md b/README.md
index 909cc95..f7f32cc 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ Read instruction for tocken in ~/.m2/setting.xml
release:
+export PATH=/usr/lib/jvm/java-18-openjdk/bin:$PATH
mvn install
mvn deploy
diff --git a/pom.xml b/pom.xml
index 1a61609..80dd7f6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
kangaroo-and-rabbit
archidata
- 0.1.2
+ 0.1.3
2.1
2.32
diff --git a/src/org/kar/archidata/GlobalConfiguration.java b/src/org/kar/archidata/GlobalConfiguration.java
index 7e18866..65a46c5 100644
--- a/src/org/kar/archidata/GlobalConfiguration.java
+++ b/src/org/kar/archidata/GlobalConfiguration.java
@@ -4,7 +4,7 @@ import org.kar.archidata.db.DBConfig;
import org.kar.archidata.util.ConfigBaseVariable;
public class GlobalConfiguration {
- public static DBConfig dbConfig = null;;
+ public static DBConfig dbConfig = null;
static {
dbConfig = new DBConfig(ConfigBaseVariable.getDBHost(),
diff --git a/src/org/kar/archidata/SqlWrapper.java b/src/org/kar/archidata/SqlWrapper.java
index 34e7d9e..d16ae6a 100644
--- a/src/org/kar/archidata/SqlWrapper.java
+++ b/src/org/kar/archidata/SqlWrapper.java
@@ -520,9 +520,42 @@ public class SqlWrapper {
}
}
+ static void addElement(PreparedStatement ps, Object value, int iii) throws Exception {
+ 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 if (value.getClass() == Float.class) {
+ ps.setFloat(iii, (Float)value);
+ } else if (value.getClass() == Double.class) {
+ ps.setDouble(iii, (Double)value);
+ } else if (value.getClass() == Boolean.class) {
+ ps.setBoolean(iii, (Boolean)value);
+ } else if (value.getClass() == Boolean.class) {
+ ps.setBoolean(iii, (Boolean)value);
+ } else if (value.getClass() == Timestamp.class) {
+ ps.setTimestamp(iii, (Timestamp)value);
+ } else if (value.getClass() == Date.class) {
+ ps.setDate(iii, (Date)value);
+ } else {
+ throw new Exception("Not manage type ==> need to add it ...");
+ }
+ }
+
public static T getWith(Class clazz, String key, String value) throws Exception {
- //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) {
-
+ return getWhere(clazz, key, "=", value);
+ }
+
+ public static T getWhere(Class clazz, String key, String operator, Object value ) throws Exception {
+ return getWhere(clazz, key, operator, value, null, null, null);
+ }
+ public static T getWhere(Class clazz, String key, String operator, Object value, String key2, String operator2, Object value2 ) throws Exception {
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
T out = null;
// real add in the BDD:
@@ -535,13 +568,8 @@ public class SqlWrapper {
//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;
@@ -564,17 +592,28 @@ public class SqlWrapper {
query.append(" ");
query.append(tableName);
query.append(".");
+
query.append(name);
}
- query.append("\n FROM `");
+ query.append(" FROM `");
query.append(tableName);
query.append("` ");
- query.append("\n WHERE ");
+ query.append(" WHERE ");
query.append(tableName);
query.append(".");
query.append(key);
- query.append(" = ?");
- query.append("\n LIMIT 1 ");
+ query.append(" ");
+ query.append(operator);
+ query.append(" ?");
+ if (key2 != null) {
+ query.append(" AND ");
+ query.append(tableName);
+ query.append(".");
+ query.append(key2);
+ query.append(" ");
+ query.append(operator2);
+ query.append(" ?");
+ }
/*
query.append(" AND ");
query.append(tableName);
@@ -585,7 +624,10 @@ public class SqlWrapper {
// prepare the request:
PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
int iii = 1;
- ps.setString(iii++, value);
+ addElement(ps, value, iii++);
+ if (key2 != null) {
+ addElement(ps, value2, iii++);
+ }
// execute the request
ResultSet rs = ps.executeQuery();
while (rs.next()) {
@@ -621,11 +663,9 @@ public class SqlWrapper {
entry = null;
return out;
}
-
- public static T getWhere(Class clazz, String key, String operator, Object value ) throws Exception {
-
+ public static List getsWhere(Class clazz, String key, String operator, Object value ) throws Exception {
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
- T out = null;
+ List outs = new ArrayList<>();
// real add in the BDD:
try {
String tableName = getTableName(clazz);
@@ -683,31 +723,7 @@ public class SqlWrapper {
// 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 if (value.getClass() == Float.class) {
- ps.setFloat(iii++, (Float)value);
- } else if (value.getClass() == Double.class) {
- ps.setDouble(iii++, (Double)value);
- } else if (value.getClass() == Boolean.class) {
- ps.setBoolean(iii++, (Boolean)value);
- } else if (value.getClass() == Boolean.class) {
- ps.setBoolean(iii++, (Boolean)value);
- } else if (value.getClass() == Timestamp.class) {
- ps.setTimestamp(iii++, (Timestamp)value);
- } else if (value.getClass() == Date.class) {
- ps.setDate(iii++, (Date)value);
- } else {
- throw new Exception("Not manage type ==> need to add it ...");
- }
+ addElement(ps, value, iii++);
// execute the request
ResultSet rs = ps.executeQuery();
while (rs.next()) {
@@ -733,7 +749,8 @@ public class SqlWrapper {
setValueFromDb(elem.getType(), data, count, elem, rs);
count++;
}
- out = (T)data;
+ T out = (T)data;
+ outs.add(out);
}
} catch (SQLException ex) {
@@ -741,7 +758,7 @@ public class SqlWrapper {
}
entry.disconnect();
entry = null;
- return out;
+ return outs;
}
public static T get(Class clazz, long id) throws Exception {
@@ -1021,6 +1038,22 @@ public class SqlWrapper {
entry.disconnect();
}
}
+ public static void unsetDelete(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`=false 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);
diff --git a/src/org/kar/archidata/UpdateJwtPublicKey.java b/src/org/kar/archidata/UpdateJwtPublicKey.java
index a8e0594..74c6897 100644
--- a/src/org/kar/archidata/UpdateJwtPublicKey.java
+++ b/src/org/kar/archidata/UpdateJwtPublicKey.java
@@ -6,12 +6,6 @@ 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 {
diff --git a/src/org/kar/archidata/UserDB.java b/src/org/kar/archidata/UserDB.java
index d638e1e..aacf29b 100755
--- a/src/org/kar/archidata/UserDB.java
+++ b/src/org/kar/archidata/UserDB.java
@@ -13,76 +13,17 @@ public class 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);
diff --git a/src/org/kar/archidata/annotation/SQLForeignKey.java b/src/org/kar/archidata/annotation/SQLForeignKey.java
new file mode 100644
index 0000000..be8189d
--- /dev/null
+++ b/src/org/kar/archidata/annotation/SQLForeignKey.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 SQLForeignKey {
+ String value();
+}
diff --git a/src/org/kar/archidata/annotation/security/PermitTokenInURI.java b/src/org/kar/archidata/annotation/security/PermitTokenInURI.java
index ce9f632..09d2442 100644
--- a/src/org/kar/archidata/annotation/security/PermitTokenInURI.java
+++ b/src/org/kar/archidata/annotation/security/PermitTokenInURI.java
@@ -5,7 +5,6 @@ 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
diff --git a/src/org/kar/archidata/api/DataResource.java b/src/org/kar/archidata/api/DataResource.java
new file mode 100644
index 0000000..519c487
--- /dev/null
+++ b/src/org/kar/archidata/api/DataResource.java
@@ -0,0 +1,429 @@
+package org.kar.archidata.api;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.kar.archidata.filter.GenericContext;
+import org.kar.archidata.model.Data;
+import org.kar.archidata.SqlWrapper;
+import org.kar.archidata.annotation.security.PermitTokenInURI;
+import org.kar.archidata.annotation.security.RolesAllowed;
+import org.kar.archidata.util.ConfigBaseVariable;
+
+import javax.imageio.ImageIO;
+import javax.ws.rs.*;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.StreamingOutput;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+
+
+// https://stackoverflow.com/questions/35367113/jersey-webservice-scalable-approach-to-download-file-and-reply-to-client
+// https://gist.github.com/aitoroses/4f7a2b197b732a6a691d
+
+@Path("/data")
+@Produces({MediaType.APPLICATION_JSON})
+public class DataResource {
+ private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
+ private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
+ /**
+ * Upload some datas
+ */
+ private static long tmpFolderId = 1;
+
+ private static void createFolder(String path) throws IOException {
+ if (!Files.exists(java.nio.file.Path.of(path))) {
+ //Log.print("Create folder: " + path);
+ Files.createDirectories(java.nio.file.Path.of(path));
+ }
+ }
+
+ public static long getTmpDataId() {
+ return tmpFolderId++;
+ }
+
+ public static String getTmpFileInData(long tmpFolderId) {
+ String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
+ try {
+ createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return filePath;
+ }
+
+ public static String getFileData(long tmpFolderId) {
+ String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
+ try {
+ createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return filePath;
+ }
+
+ public static Data getWithSha512(String sha512) {
+ System.out.println("find sha512 = " + sha512);
+ try {
+ return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static Data getWithId(long id) {
+ System.out.println("find id = " + id);
+ try {
+ return SqlWrapper.get(Data.class, id);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException {
+ // determine mime type:
+ Data injectedData = new Data();
+ String mimeType = "";
+ String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
+ switch (extension.toLowerCase()) {
+ case "jpg":
+ case "jpeg":
+ mimeType = "image/jpeg";
+ break;
+ case "png":
+ mimeType = "image/png";
+ break;
+ case "webp":
+ mimeType = "image/webp";
+ break;
+ case "mka":
+ mimeType = "audio/x-matroska";
+ break;
+ case "mkv":
+ mimeType = "video/x-matroska";
+ break;
+ case "webm":
+ mimeType = "video/webm";
+ break;
+ default:
+ throw new IOException("Can not find the mime type of data input: '" + extension + "'");
+ }
+ injectedData.mimeType = mimeType;
+ injectedData.sha512 = sha512;
+ String tmpPath = getTmpFileInData(tmpUID);
+ injectedData.size = Files.size(Paths.get(tmpPath));
+
+ try {
+ injectedData = SqlWrapper.insert(injectedData);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ String mediaPath = getFileData(injectedData.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");
+ return injectedData;
+ }
+
+ public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
+ return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
+ }
+
+ public static void removeTemporaryFile(long idData) {
+ String filepath = DataResource.getTmpFileInData(idData);
+ if (Files.exists(Paths.get(filepath))) {
+ try {
+ Files.delete(Paths.get(filepath));
+ } catch (IOException e) {
+ System.out.println("can not delete temporary file : " + Paths.get(filepath));
+ e.printStackTrace();
+ }
+ }
+ }
+
+ // save uploaded file to a defined location on the server
+ static String saveFile(InputStream uploadedInputStream, String serverLocation) {
+ String out = "";
+ try {
+ OutputStream outpuStream = new FileOutputStream(new File(
+ serverLocation));
+ int read = 0;
+ byte[] bytes = new byte[CHUNK_SIZE_IN];
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+
+ outpuStream = new FileOutputStream(new File(serverLocation));
+ while ((read = uploadedInputStream.read(bytes)) != -1) {
+ //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;
+ }
+
+ public static String bytesToHex(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x", b));
+ }
+ return sb.toString();
+ }
+
+
+ public Data getSmall(Long id) {
+ try {
+ return SqlWrapper.get(Data.class, id);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @POST
+ @Path("/upload/")
+ @Consumes({MediaType.MULTIPART_FORM_DATA})
+ @RolesAllowed("ADMIN")
+ public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) {
+ GenericContext gc = (GenericContext) sc.getUserPrincipal();
+ System.out.println("===================================================");
+ System.out.println("== DATA uploadFile " + (gc==null?"null":gc.user));
+ System.out.println("===================================================");
+ //public NodeSmall uploadFile(final FormDataMultiPart form) {
+ System.out.println("Upload file: ");
+ String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
+ try {
+ createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ saveFile(fileInputStream, filePath);
+ return Response.ok("Data uploaded successfully !!").build();
+ //return null;
+ }
+
+ @GET
+ @Path("{id}")
+ @PermitTokenInURI
+ @RolesAllowed("USER")
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
+ GenericContext gc = (GenericContext) sc.getUserPrincipal();
+ //System.out.println("===================================================");
+ System.out.println("== DATA retriveDataId ? id=" + id + " user=" + (gc==null?"null":gc.user));
+ //System.out.println("===================================================");
+ Data value = getSmall(id);
+ if (value == null) {
+ Response.status(404).
+ entity("media NOT FOUND: " + id).
+ type("text/plain").
+ build();
+ }
+ return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
+ }
+
+ @GET
+ @Path("thumbnail/{id}")
+ @RolesAllowed("USER")
+ @PermitTokenInURI
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ //@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
+ public Response retriveDataThumbnailId(@Context SecurityContext sc,
+ @QueryParam(HttpHeaders.AUTHORIZATION) String token,
+ @HeaderParam("Range") String range,
+ @PathParam("id") Long id) throws Exception {
+ GenericContext gc = (GenericContext) sc.getUserPrincipal();
+ //System.out.println("===================================================");
+ //System.out.println("== DATA retriveDataThumbnailId ? " + (gc==null?"null":gc.user));
+ //System.out.println("===================================================");
+ Data value = getSmall(id);
+ if (value == null) {
+ return Response.status(404).
+ entity("media NOT FOUND: " + id).
+ type("text/plain").
+ build();
+ }
+ String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
+ if ( value.mimeType.contentEquals("image/jpeg")
+ || value.mimeType.contentEquals("image/png")
+ // || value.mimeType.contentEquals("image/webp")
+ ) {
+ // reads input image
+ //System.out.println("Read path: " + filePathName);
+ File inputFile = new File(filePathName);
+ if (!inputFile.exists()) {
+ return Response.status(500).
+ entity("Internal Error: Media is NOT FOUNDABLE: " + id).
+ type("text/plain").
+ build();
+ }
+ BufferedImage inputImage = ImageIO.read(inputFile);
+ int scaledWidth = 250;
+ int scaledHeight = (int)((float)inputImage.getHeight() / (float)inputImage.getWidth() * (float) scaledWidth);
+ // creates output image
+ BufferedImage outputImage = new BufferedImage(scaledWidth,
+ scaledHeight, inputImage.getType());
+
+ // scales the input image to the output image
+ Graphics2D g2d = outputImage.createGraphics();
+ g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
+ g2d.dispose();
+ // create the output stream:
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ // TODO: check how to remove buffer file !!! here, it is not needed at all...
+ ImageIO.write( outputImage, "JPG", baos);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return Response.status(500).
+ entity("Internal Error: resize fail: " + e.getMessage()).
+ type("text/plain").
+ build();
+ }
+ byte[] imageData = baos.toByteArray();
+ //Response.ok(new ByteArrayInputStream(imageData)).build();
+ Response.ResponseBuilder out = Response.ok(imageData)
+ .header(HttpHeaders.CONTENT_LENGTH, imageData.length);
+ out.type("image/jpeg");
+ // TODO: move this in a decorator !!!
+ CacheControl cc = new CacheControl();
+ cc.setMaxAge(3600);
+ cc.setNoCache(false);
+ out.cacheControl(cc);
+ return out.build();
+ }
+ return buildStream(filePathName, range, value.mimeType);
+ }
+ //@Secured
+ @GET
+ @Path("{id}/{name}")
+ @PermitTokenInURI
+ @RolesAllowed("USER")
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id, @PathParam("name") String name) throws Exception {
+ GenericContext gc = (GenericContext) sc.getUserPrincipal();
+ //System.out.println("===================================================");
+ System.out.println("== DATA retriveDataFull ? id=" + id + " user=" + (gc==null?"null":gc.user));
+ //System.out.println("===================================================");
+ Data value = getSmall(id);
+ if (value == null) {
+ Response.status(404).
+ entity("media NOT FOUND: " + id).
+ type("text/plain").
+ build();
+ }
+ return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
+ }
+
+ /**
+ * Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541
+ *
+ * @param range range header
+ * @return Streaming output
+ * @throws Exception IOException if an error occurs in streaming.
+ */
+ private Response buildStream(final String filename, final String range, String mimeType) throws Exception {
+ File file = new File(filename);
+ //System.out.println("request range : " + range);
+ // range not requested : Firefox does not send range headers
+ if (range == null) {
+ final StreamingOutput output = new StreamingOutput() {
+ @Override
+ public void write(OutputStream out) {
+ try (FileInputStream in = new FileInputStream(file)) {
+ byte[] buf = new byte[1024 * 1024];
+ int len;
+ while ((len = in.read(buf)) != -1) {
+ try {
+ out.write(buf, 0, len);
+ out.flush();
+ //System.out.println("---- wrote " + len + " bytes file ----");
+ } catch (IOException ex) {
+ System.out.println("remote close connection");
+ break;
+ }
+ }
+ } catch (IOException ex) {
+ throw new InternalServerErrorException(ex);
+ }
+ }
+ };
+ Response.ResponseBuilder out = Response.ok(output)
+ .header(HttpHeaders.CONTENT_LENGTH, file.length());
+ if (mimeType != null) {
+ out.type(mimeType);
+ }
+ return out.build();
+
+ }
+
+ String[] ranges = range.split("=")[1].split("-");
+ final long from = Long.parseLong(ranges[0]);
+
+ //System.out.println("request range : " + ranges.length);
+ //Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
+ long to = CHUNK_SIZE + from;
+ if (ranges.length == 1) {
+ to = file.length() - 1;
+ } else {
+ if (to >= file.length()) {
+ to = (long) (file.length() - 1);
+ }
+ }
+ final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
+ //System.out.println("responseRange : " + responseRange);
+ final RandomAccessFile raf = new RandomAccessFile(file, "r");
+ raf.seek(from);
+
+ final long len = to - from + 1;
+ final MediaStreamer streamer = new MediaStreamer(len, raf);
+ Response.ResponseBuilder out = Response.ok(streamer)
+ .status(Response.Status.PARTIAL_CONTENT)
+ .header("Accept-Ranges", "bytes")
+ .header("Content-Range", responseRange)
+ .header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth())
+ .header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified()));
+ if (mimeType != null) {
+ out.type(mimeType);
+ }
+ return out.build();
+ }
+
+ public static void undelete(Long id) throws Exception {
+ SqlWrapper.unsetDelete(Data.class, id);
+ }
+
+}
diff --git a/src/org/kar/archidata/api/MediaStreamer.java b/src/org/kar/archidata/api/MediaStreamer.java
new file mode 100644
index 0000000..1ad626d
--- /dev/null
+++ b/src/org/kar/archidata/api/MediaStreamer.java
@@ -0,0 +1,56 @@
+package org.kar.archidata.api;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+public class MediaStreamer implements StreamingOutput {
+ private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
+ final byte[] buf = new byte[CHUNK_SIZE];
+ private long length;
+ private RandomAccessFile raf;
+
+ public MediaStreamer(long length, RandomAccessFile raf) throws IOException {
+ //System.out.println("request stream of " + length / 1024 + " data");
+ if (length<0) {
+ throw new IOException("Wrong size of the file to stream: " + length);
+ }
+ this.length = length;
+ this.raf = raf;
+ }
+
+ @Override
+ public void write(OutputStream outputStream) {
+ try {
+ while (length != 0) {
+ int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length);
+ try {
+ outputStream.write(buf, 0, read);
+ } catch (IOException ex) {
+ System.out.println("remote close connection");
+ break;
+ }
+ length -= read;
+ }
+ } catch (IOException ex) {
+ throw new InternalServerErrorException(ex);
+ } catch (WebApplicationException ex) {
+ throw new InternalServerErrorException(ex);
+ } finally {
+ try {
+ raf.close();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ throw new InternalServerErrorException(ex);
+ }
+ }
+ }
+
+ public long getLenth() {
+ return length;
+ }
+
+}
diff --git a/src/org/kar/archidata/model/Data.java b/src/org/kar/archidata/model/Data.java
index a34617a..eabda46 100644
--- a/src/org/kar/archidata/model/Data.java
+++ b/src/org/kar/archidata/model/Data.java
@@ -3,30 +3,29 @@ package org.kar.archidata.model;
import java.sql.ResultSet;
import java.sql.SQLException;
-public class Data {
- public Long id;
- public boolean deleted;
+import org.kar.archidata.annotation.SQLComment;
+import org.kar.archidata.annotation.SQLIfNotExists;
+import org.kar.archidata.annotation.SQLLimitSize;
+import org.kar.archidata.annotation.SQLNotNull;
+import org.kar.archidata.annotation.SQLTableName;
+import org.kar.archidata.model.GenericTable;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@SQLTableName ("data")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class Data extends GenericTable {
+
+ @SQLNotNull
+ @SQLLimitSize(128)
+ @SQLComment("Sha512 of the data")
public String sha512;
+ @SQLNotNull
+ @SQLLimitSize(128)
+ @SQLComment("Mime -type of the media")
public String mimeType;
+ @SQLNotNull
+ @SQLComment("Size in Byte of the data")
public Long size;
-
- 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/User.java b/src/org/kar/archidata/model/User.java
index 535ccd0..06f20f3 100644
--- a/src/org/kar/archidata/model/User.java
+++ b/src/org/kar/archidata/model/User.java
@@ -30,12 +30,7 @@ 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;
+public class User extends GenericTable {
@SQLLimitSize(128)
public String login = null;
diff --git a/src/org/kar/archidata/model/UserSmall.java b/src/org/kar/archidata/model/UserSmall.java
deleted file mode 100644
index 91cb8e8..0000000
--- a/src/org/kar/archidata/model/UserSmall.java
+++ /dev/null
@@ -1,73 +0,0 @@
-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/DataTools.java b/src/org/kar/archidata/util/DataTools.java
index 431fc9a..89e9887 100644
--- a/src/org/kar/archidata/util/DataTools.java
+++ b/src/org/kar/archidata/util/DataTools.java
@@ -73,43 +73,23 @@ public class DataTools {
}
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;
-
+ try {
+ return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ 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;
+ try {
+ return SqlWrapper.getWhere(Data.class, "deleted", "=", false, "id", "=", id);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
}
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException, SQLException {
@@ -141,41 +121,20 @@ public class DataTools {
}
String tmpPath = getTmpFileInData(tmpUID);
long fileSize = Files.size(Paths.get(tmpPath));
- DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
- long uniqueSQLID = -1;
+ Data out = new Data();;
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).");
- }
+ out.sha512 = sha512;
+ out.mimeType = mimeType;
+ out.size = fileSize;
+ out = SqlWrapper.insert(out);
} catch (SQLException ex) {
ex.printStackTrace();
- }
- entry.disconnect();
- System.out.println("Add Data raw done. uid data=" + uniqueSQLID);
- Data out = getWithId(uniqueSQLID);
+ return null;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
String mediaPath = getFileData(out.id);
System.out.println("src = " + tmpPath);
@@ -183,22 +142,17 @@ public class DataTools {
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
System.out.println("Move done");
- // all is done the file is corectly installed...
-
+ // all is done the file is correctly 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();
+ try {
+ SqlWrapper.unsetDelete(Data.class, id);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {