[FEAT] someting is wrong

This commit is contained in:
Edouard DUPIN 2024-09-12 00:24:37 +02:00
parent 37f1362c3c
commit de08bcfab5
7 changed files with 300 additions and 84 deletions

View File

@ -25,21 +25,24 @@
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations"> <classpathentry kind="src" path="target/generated-sources/annotations">
<attributes> <attributes>
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
</classpath> </classpath>

28
pom.xml
View File

@ -54,6 +54,31 @@
<version>2.1.0-alpha1</version> <version>2.1.0-alpha1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Decode webP images -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-webp</artifactId>
<version>3.11.0</version>
</dependency>
<!-- Decode JPEG image -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.11.0</version>
</dependency>
<!-- Encode file in webp -->
<dependency>
<groupId>com.github.gotson</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.2.2</version>
</dependency>
<!-- Detect type of a file with mime type -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart --> <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
<dependency> <dependency>
<groupId>org.glassfish.jersey.media</groupId> <groupId>org.glassfish.jersey.media</groupId>
@ -96,11 +121,13 @@
<artifactId>istack-commons-runtime</artifactId> <artifactId>istack-commons-runtime</artifactId>
<version>${istack.version}</version> <version>${istack.version}</version>
</dependency> </dependency>
<!-- continu to be needed ??? -->
<dependency> <dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId> <groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId> <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Serialize and un-serialize request in JSON-->
<dependency> <dependency>
<groupId>org.glassfish.jersey.media</groupId> <groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId> <artifactId>jersey-media-json-jackson</artifactId>
@ -110,6 +137,7 @@
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>2.17.1</version> <version>2.17.1</version>
</dependency> </dependency>
<!-- encode output in CSV -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId> <groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId> <artifactId>jackson-dataformat-csv</artifactId>

View File

@ -326,10 +326,10 @@ public class DataResource {
@QueryParam(HttpHeaders.AUTHORIZATION) final String token, @QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range, @HeaderParam("Range") final String range,
@PathParam("uuid") final UUID uuid) throws FailException { @PathParam("uuid") final UUID uuid) throws FailException {
// GenericContext gc = (GenericContext) sc.getUserPrincipal(); final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("==================================================="); LOGGER.info("===================================================");
// logger.info("== DATA retrieveDataThumbnailId ? {}", (gc==null?"null":gc.user)); LOGGER.info("== DATA retrieveDataThumbnailId ? {}", (gc == null ? "null" : gc.userByToken));
// logger.info("==================================================="); LOGGER.info("===================================================");
final Data value = getSmall(uuid); final Data value = getSmall(uuid);
if (value == null) { if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + uuid).type("text/plain").build(); return Response.status(404).entity("media NOT FOUND: " + uuid).type("text/plain").build();
@ -350,31 +350,43 @@ public class DataResource {
} catch (final IOException ex) { } catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to READ the image", ex); throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to READ the image", ex);
} }
LOGGER.info("input size image: {}x{} type={}", inputImage.getWidth(), inputImage.getHeight(),
inputImage.getType());
final int scaledWidth = 250; final int scaledWidth = 250;
final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth()
* scaledWidth); * scaledWidth);
// creates output image // creates output image
final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType()); final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
// scales the input image to the output image // scales the input image to the output image
final Graphics2D g2d = outputImage.createGraphics(); final Graphics2D g2d = outputImage.createGraphics();
LOGGER.info("output size image: {}x{}", scaledWidth, scaledHeight);
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null); g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose(); g2d.dispose();
for (final String data : ImageIO.getWriterFormatNames()) {
LOGGER.info("availlable format: {}", data);
}
// create the output stream: // create the output stream:
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { try {
// TODO: check how to remove buffer file !!! here, it is not needed at all... // TODO: check how to remove buffer file !!! here, it is not needed at all...
ImageIO.write(outputImage, "JPG", baos); //ImageIO.write(outputImage, "JPEG", baos);
//ImageIO.write(outputImage, "png", baos);
ImageIO.write(outputImage, "WebP", baos);
} catch (final IOException e) { } catch (final IOException e) {
e.printStackTrace(); e.printStackTrace();
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain") return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain")
.build(); .build();
} }
final byte[] imageData = baos.toByteArray(); final byte[] imageData = baos.toByteArray();
LOGGER.info("output length {}", imageData.length);
// Response.ok(new ByteArrayInputStream(imageData)).build(); // Response.ok(new ByteArrayInputStream(imageData)).build();
final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH,
imageData.length); imageData.length);
out.type("image/jpeg"); //out.type("image/jpeg");
out.type("image/webp");
//out.type("image/png");
// TODO: move this in a decorator !!! // TODO: move this in a decorator !!!
final CacheControl cc = new CacheControl(); final CacheControl cc = new CacheControl();
cc.setMaxAge(3600); cc.setMaxAge(3600);

View File

@ -0,0 +1,43 @@
package org.kar.archidata.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Path("/proxy")
//@Produces(MediaType.APPLICATION_JSON)
public class ProxyResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ProxyResource.class);
@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getImageFromUrl(@QueryParam("url") final String url) {
if (url == null || url.isEmpty()) {
return Response.status(Status.BAD_REQUEST).entity("URL manquante").build();
}
final Client client = ClientBuilder.newClient();
try {
final WebTarget target = client.target(url);
final Response response = target.request().get();
if (response.getStatus() != 200) {
return Response.status(Status.BAD_GATEWAY).entity("Can not get the image : " + response.getStatus())
.build();
}
return Response.ok(response.readEntity(byte[].class)).header("Access-Control-Allow-Origin", "*")
.header("Content-Type", response.getHeaderString("Content-Type")).build();
} catch (final Exception e) {
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("SERVER internal error : " + e.getMessage())
.build();
}
}
}

View File

@ -11,9 +11,11 @@ import java.nio.file.StandardCopyOption;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.apache.tika.Tika;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.api.DataResource; import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
@ -28,6 +30,9 @@ import org.kar.archidata.model.Data;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
public class DataTools { public class DataTools {
@ -37,6 +42,9 @@ public class DataTools {
public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/** Upload some data */ /** Upload some data */
private static long tmpFolderId = 1; private static long tmpFolderId = 1;
public final static String[] SUPPORTED_IMAGE_MIME_TYPE = { "image/jpeg", "image/png", "image/webp" };
public final static String[] SUPPORTED_AUDIO_MIME_TYPE = { "audio/x-matroska" };
public final static String[] SUPPORTED_VIDEO_MIME_TYPE = { "video/x-matroska", "video/webm" };
public static void createFolder(final String path) throws IOException { public static void createFolder(final String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) { if (!Files.exists(java.nio.file.Path.of(path))) {
@ -91,20 +99,12 @@ public class DataTools {
return null; return null;
} }
public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512) public static Data createNewData(
throws IOException, SQLException { final long tmpUID,
// determine mime type: final String originalFileName,
String mimeType = ""; final String sha512,
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); final String mimeType) throws IOException, SQLException {
mimeType = switch (extension.toLowerCase()) {
case "jpg", "jpeg" -> "image/jpeg";
case "png" -> "image/png";
case "webp" -> "image/webp";
case "mka" -> "audio/x-matroska";
case "mkv" -> "video/x-matroska";
case "webm" -> "video/webm";
default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'");
};
final String tmpPath = getTmpFileInData(tmpUID); final String tmpPath = getTmpFileInData(tmpUID);
final long fileSize = Files.size(Paths.get(tmpPath)); final long fileSize = Files.size(Paths.get(tmpPath));
Data out = new Data(); Data out = new Data();
@ -130,6 +130,23 @@ public class DataTools {
return out; return out;
} }
public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
throws IOException, SQLException {
// determine mime type:
String mimeType = "";
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
mimeType = switch (extension.toLowerCase()) {
case "jpg", "jpeg" -> "image/jpeg";
case "png" -> "image/png";
case "webp" -> "image/webp";
case "mka" -> "audio/x-matroska";
case "mkv" -> "video/x-matroska";
case "webm" -> "video/webm";
default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'");
};
return createNewData(tmpUID, originalFileName, sha512, mimeType);
}
public static void undelete(final UUID id) { public static void undelete(final UUID id) {
try { try {
DataAccess.unsetDelete(Data.class, id); DataAccess.unsetDelete(Data.class, id);
@ -143,6 +160,10 @@ public class DataTools {
return saveFile(uploadedInputStream, getTmpFileInData(idData)); return saveFile(uploadedInputStream, getTmpFileInData(idData));
} }
public static String saveTemporaryFile(final byte[] uploadedInputStream, final long idData) {
return saveFile(uploadedInputStream, getTmpFileInData(idData));
}
public static void removeTemporaryFile(final long idData) { public static void removeTemporaryFile(final long idData) {
final String filepath = getTmpFileInData(idData); final String filepath = getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) { if (Files.exists(Paths.get(filepath))) {
@ -188,6 +209,31 @@ public class DataTools {
return out; return out;
} }
public static String saveFile(final byte[] bytes, final String serverLocation) {
String out = "";
try {
final OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
final MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(bytes, 0, bytes.length);
outpuStream.write(bytes, 0, bytes.length);
LOGGER.info("Flush input stream ... {}", serverLocation);
outpuStream.flush();
outpuStream.close();
// create the end of sha512
final byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
} catch (final IOException ex) {
LOGGER.error("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (final NoSuchAlgorithmException ex) {
LOGGER.error("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
// curl http://localhost:9993/api/users/3 // curl http://localhost:9993/api/users/3
// @Secured // @Secured
/* @GET /* @GET
@ -216,6 +262,90 @@ public class DataTools {
return data; return data;
} }
public static String getMimeType(final byte[] data) {
final Tika tika = new Tika();
final String mimeType = tika.detect(data);
return mimeType;
}
public static <CLASS_TYPE, ID_TYPE> void uploadCoverFromUri(
final Class<CLASS_TYPE> clazz,
final ID_TYPE id,
final String url) throws Exception {
LOGGER.info(" - id: {}", id);
LOGGER.info(" - url: {} ", url);
final CLASS_TYPE media = DataAccess.get(clazz, id);
if (media == null) {
throw new InputException(clazz.getCanonicalName(),
"[" + id.toString() + "] Id does not exist or removed...");
}
// Download data:
final Client client = ClientBuilder.newClient();
byte[] dataResponse = null;
try {
final WebTarget target = client.target(url);
final Response response = target.request().get();
if (response.getStatus() != 200) {
throw new FailException(Response.Status.BAD_GATEWAY,
clazz.getCanonicalName() + "[" + id.toString() + "] Can not download the media");
}
dataResponse = response.readEntity(byte[].class);
} catch (final Exception ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR,
clazz.getCanonicalName() + "[" + id.toString() + "] can not create input media", ex);
}
if (dataResponse == null) {
throw new FailException(Response.Status.NOT_ACCEPTABLE,
clazz.getCanonicalName() + "[" + id.toString() + "] Data does not exist");
}
if (dataResponse.length == 0 || dataResponse.length == 50 * 1024 * 1024) {
throw new FailException(Response.Status.NOT_ACCEPTABLE, clazz.getCanonicalName() + "[" + id.toString()
+ "] Data size is not correct " + dataResponse.length);
}
final long tmpUID = getTmpDataId();
final String sha512 = saveTemporaryFile(dataResponse, tmpUID);
Data data = getWithSha512(sha512);
final String mimeType = getMimeType(dataResponse);
if (!Arrays.asList(SUPPORTED_IMAGE_MIME_TYPE).contains(mimeType)) {
throw new FailException(Response.Status.NOT_ACCEPTABLE,
clazz.getCanonicalName() + "[" + id.toString() + "] Data CoverType is not accesptable: " + mimeType
+ "support only: " + String.join(", ", SUPPORTED_IMAGE_MIME_TYPE));
}
if (data == null) {
LOGGER.info("Need to add the data in the BDD ... ");
try {
data = createNewData(tmpUID, url, sha512, mimeType);
} catch (final IOException ex) {
removeTemporaryFile(tmpUID);
throw new FailException(Response.Status.NOT_MODIFIED,
clazz.getCanonicalName() + "[" + id.toString() + "] can not create input media", ex);
} catch (final SQLException ex) {
removeTemporaryFile(tmpUID);
throw new FailException(Response.Status.NOT_MODIFIED,
clazz.getCanonicalName() + "[" + id.toString() + "] Error in SQL insertion", ex);
}
} else if (data.deleted) {
LOGGER.error("Data already exist but deleted");
undelete(data.uuid);
data.deleted = false;
} else {
LOGGER.error("Data already exist ... all good");
}
// Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode");
if (id instanceof final Long idLong) {
AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid);
} else if (id instanceof final UUID idUUID) {
AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid);
} else {
throw new IOException("Fail to add Cover can not detect type...");
}
}
public static <CLASS_TYPE, ID_TYPE> void uploadCover( public static <CLASS_TYPE, ID_TYPE> void uploadCover(
final Class<CLASS_TYPE> clazz, final Class<CLASS_TYPE> clazz,
final ID_TYPE id, final ID_TYPE id,

View File

@ -107,7 +107,7 @@ public class JWTWrapper {
} }
in.close(); in.close();
// print result // print result
// LOGGER.debug(response.toString()); LOGGER.debug(response.toString());
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper = new ObjectMapper();
final PublicKey values = mapper.readValue(response.toString(), PublicKey.class); final PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
rsaPublicJWK = RSAKey.parse(values.key); rsaPublicJWK = RSAKey.parse(values.key);