[DEV] remove generic annotation and test json update
This commit is contained in:
parent
f69bc8097a
commit
c4fc49d91b
@ -1,14 +0,0 @@
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import jakarta.ws.rs.NameBinding;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD })
|
||||
public @interface DenyAll {}
|
@ -1,14 +0,0 @@
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import jakarta.ws.rs.NameBinding;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD })
|
||||
public @interface PermitAll {}
|
@ -1,16 +0,0 @@
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import jakarta.ws.rs.NameBinding;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD })
|
||||
public @interface RolesAllowed {
|
||||
String[] value();
|
||||
}
|
@ -22,15 +22,15 @@ import javax.imageio.ImageIO;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.kar.archidata.annotation.security.PermitTokenInURI;
|
||||
import org.kar.archidata.annotation.security.RolesAllowed;
|
||||
import org.kar.archidata.dataAccess.QueryCondition;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.QueryCondition;
|
||||
import org.kar.archidata.filter.GenericContext;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.util.ConfigBaseVariable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.HeaderParam;
|
||||
@ -61,133 +61,119 @@ public class DataResource {
|
||||
* Upload some datas
|
||||
*/
|
||||
private static long tmpFolderId = 1;
|
||||
|
||||
private static void createFolder(String path) throws IOException {
|
||||
|
||||
private static void createFolder(final 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;
|
||||
|
||||
public static String getTmpFileInData(final long tmpFolderId) {
|
||||
final String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
|
||||
try {
|
||||
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public static String getFileData(long tmpFolderId) {
|
||||
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
|
||||
|
||||
public static String getFileData(final long tmpFolderId) {
|
||||
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
|
||||
try {
|
||||
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public static Data getWithSha512(String sha512) {
|
||||
|
||||
public static Data getWithSha512(final String sha512) {
|
||||
LOGGER.info("find sha512 = {}", sha512);
|
||||
try {
|
||||
return DataAccess.getWhere(Data.class, new QueryCondition("sha512", "=", sha512));
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Data getWithId(long id) {
|
||||
|
||||
public static Data getWithId(final long id) {
|
||||
LOGGER.info("find id = {}", id);
|
||||
try {
|
||||
return DataAccess.get(Data.class, id);
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException {
|
||||
public static Data createNewData(final long tmpUID, final String originalFileName, final 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 + "'");
|
||||
}
|
||||
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 + "'");
|
||||
};
|
||||
injectedData.mimeType = mimeType;
|
||||
injectedData.sha512 = sha512;
|
||||
String tmpPath = getTmpFileInData(tmpUID);
|
||||
final String tmpPath = getTmpFileInData(tmpUID);
|
||||
injectedData.size = Files.size(Paths.get(tmpPath));
|
||||
|
||||
|
||||
try {
|
||||
injectedData = DataAccess.insert(injectedData);
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
String mediaPath = getFileData(injectedData.id);
|
||||
final String mediaPath = getFileData(injectedData.id);
|
||||
LOGGER.info("src = {}", tmpPath);
|
||||
LOGGER.info("dst = {}", mediaPath);
|
||||
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
|
||||
LOGGER.info("Move done");
|
||||
return injectedData;
|
||||
}
|
||||
|
||||
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
|
||||
|
||||
public static String saveTemporaryFile(final InputStream uploadedInputStream, final long idData) {
|
||||
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
|
||||
}
|
||||
|
||||
public static void removeTemporaryFile(long idData) {
|
||||
String filepath = DataResource.getTmpFileInData(idData);
|
||||
|
||||
public static void removeTemporaryFile(final long idData) {
|
||||
final String filepath = DataResource.getTmpFileInData(idData);
|
||||
if (Files.exists(Paths.get(filepath))) {
|
||||
try {
|
||||
Files.delete(Paths.get(filepath));
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
LOGGER.info("can not delete temporary file : {}", Paths.get(filepath));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// save uploaded file to a defined location on the server
|
||||
static String saveFile(InputStream uploadedInputStream, String serverLocation) {
|
||||
static String saveFile(final InputStream uploadedInputStream, final 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");
|
||||
|
||||
final byte[] bytes = new byte[CHUNK_SIZE_IN];
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
|
||||
outpuStream = new FileOutputStream(new File(serverLocation));
|
||||
while ((read = uploadedInputStream.read(bytes)) != -1) {
|
||||
//logger.info("write {}", read);
|
||||
@ -199,95 +185,96 @@ public class DataResource {
|
||||
outpuStream.flush();
|
||||
outpuStream.close();
|
||||
// create the end of sha512
|
||||
byte[] sha512Digest = md.digest();
|
||||
final byte[] sha512Digest = md.digest();
|
||||
// convert in hexadecimal
|
||||
out = bytesToHex(sha512Digest);
|
||||
uploadedInputStream.close();
|
||||
} catch (IOException ex) {
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.info("Can not write in temporary file ... ");
|
||||
ex.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
} catch (final NoSuchAlgorithmException ex) {
|
||||
LOGGER.info("Can not find sha512 algorithms");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
|
||||
public static String bytesToHex(final byte[] bytes) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (final byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Data getSmall(Long id) {
|
||||
|
||||
public Data getSmall(final Long id) {
|
||||
try {
|
||||
return DataAccess.get(Data.class, id);
|
||||
} catch (Exception e) {
|
||||
} catch (final 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();
|
||||
public Response uploadFile(@Context final SecurityContext sc, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
|
||||
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
|
||||
LOGGER.info("===================================================");
|
||||
LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken));
|
||||
LOGGER.info("===================================================");
|
||||
//public NodeSmall uploadFile(final FormDataMultiPart form) {
|
||||
LOGGER.info("Upload file: ");
|
||||
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
|
||||
final String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
|
||||
try {
|
||||
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
|
||||
} catch (IOException e) {
|
||||
} catch (final 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();
|
||||
public Response retriveDataId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
|
||||
@PathParam("id") final Long id) throws Exception {
|
||||
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
|
||||
//logger.info("===================================================");
|
||||
LOGGER.info("== DATA retriveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
|
||||
//logger.info("===================================================");
|
||||
Data value = getSmall(id);
|
||||
final 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 {
|
||||
public Response retriveDataThumbnailId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
|
||||
@PathParam("id") final Long id) throws Exception {
|
||||
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
|
||||
//logger.info("===================================================");
|
||||
//logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user));
|
||||
//logger.info("===================================================");
|
||||
Data value = getSmall(id);
|
||||
final Data value = getSmall(id);
|
||||
if (value == null) {
|
||||
return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
|
||||
}
|
||||
String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
|
||||
File inputFile = new File(filePathName);
|
||||
final String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
|
||||
final File inputFile = new File(filePathName);
|
||||
if (!inputFile.exists()) {
|
||||
return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build();
|
||||
}
|
||||
@ -295,31 +282,31 @@ public class DataResource {
|
||||
// || value.mimeType.contentEquals("image/webp")
|
||||
) {
|
||||
// reads input image
|
||||
BufferedImage inputImage = ImageIO.read(inputFile);
|
||||
int scaledWidth = 250;
|
||||
int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() * (float) scaledWidth);
|
||||
final BufferedImage inputImage = ImageIO.read(inputFile);
|
||||
final int scaledWidth = 250;
|
||||
final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() * scaledWidth);
|
||||
// creates output image
|
||||
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
|
||||
Graphics2D g2d = outputImage.createGraphics();
|
||||
final Graphics2D g2d = outputImage.createGraphics();
|
||||
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
|
||||
g2d.dispose();
|
||||
// create the output stream:
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final 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) {
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain").build();
|
||||
}
|
||||
byte[] imageData = baos.toByteArray();
|
||||
final byte[] imageData = baos.toByteArray();
|
||||
//Response.ok(new ByteArrayInputStream(imageData)).build();
|
||||
Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, imageData.length);
|
||||
final 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();
|
||||
final CacheControl cc = new CacheControl();
|
||||
cc.setMaxAge(3600);
|
||||
cc.setNoCache(false);
|
||||
out.cacheControl(cc);
|
||||
@ -327,26 +314,26 @@ public class DataResource {
|
||||
}
|
||||
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();
|
||||
public Response retriveDataFull(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
|
||||
@PathParam("id") final Long id, @PathParam("name") final String name) throws Exception {
|
||||
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
|
||||
//logger.info("===================================================");
|
||||
LOGGER.info("== DATA retriveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
|
||||
//logger.info("===================================================");
|
||||
Data value = getSmall(id);
|
||||
final 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
|
||||
*
|
||||
@ -354,70 +341,68 @@ public class DataResource {
|
||||
* @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);
|
||||
private Response buildStream(final String filename, final String range, final String mimeType) throws Exception {
|
||||
final File file = new File(filename);
|
||||
//logger.info("request range : {}", range);
|
||||
// range not requested : Firefox does not send range headers
|
||||
if (range == null) {
|
||||
final StreamingOutput output = new StreamingOutput() {
|
||||
@Override
|
||||
public void write(OutputStream out) {
|
||||
public void write(final OutputStream out) {
|
||||
try (FileInputStream in = new FileInputStream(file)) {
|
||||
byte[] buf = new byte[1024 * 1024];
|
||||
final byte[] buf = new byte[1024 * 1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) != -1) {
|
||||
try {
|
||||
out.write(buf, 0, len);
|
||||
out.flush();
|
||||
//logger.info("---- wrote {} bytes file ----", len);
|
||||
} catch (IOException ex) {
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.info("remote close connection");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
} catch (final IOException ex) {
|
||||
throw new InternalServerErrorException(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
Response.ResponseBuilder out = Response.ok(output).header(HttpHeaders.CONTENT_LENGTH, file.length());
|
||||
final 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 String[] ranges = range.split("=")[1].split("-");
|
||||
final long from = Long.parseLong(ranges[0]);
|
||||
|
||||
|
||||
//logger.info("request range : {}", ranges.length);
|
||||
//Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
|
||||
long to = CHUNK_SIZE + from;
|
||||
if (ranges.length == 1) {
|
||||
to = file.length() - 1;
|
||||
} else {
|
||||
if (to >= file.length()) {
|
||||
to = (long) (file.length() - 1);
|
||||
}
|
||||
} else if (to >= file.length()) {
|
||||
to = file.length() - 1;
|
||||
}
|
||||
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
|
||||
//logger.info("responseRange: {}", responseRange);
|
||||
final RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||
raf.seek(from);
|
||||
|
||||
|
||||
final long len = to - from + 1;
|
||||
final MediaStreamer streamer = new MediaStreamer(len, raf);
|
||||
Response.ResponseBuilder out = Response.ok(streamer).status(Response.Status.PARTIAL_CONTENT).header("Accept-Ranges", "bytes").header("Content-Range", responseRange)
|
||||
final 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 {
|
||||
|
||||
public static void undelete(final Long id) throws Exception {
|
||||
DataAccess.unsetDelete(Data.class, id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ package org.kar.archidata.api;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.kar.archidata.annotation.security.PermitAll;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.NotSupportedException;
|
||||
@ -19,19 +19,19 @@ import jakarta.ws.rs.core.Response.ResponseBuilder;
|
||||
|
||||
public class FrontGeneric {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FrontGeneric.class);
|
||||
|
||||
|
||||
protected String baseFrontFolder = "/data/front";
|
||||
|
||||
private String getExtension(String filename) {
|
||||
|
||||
private String getExtension(final 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);
|
||||
private Response retrive(final String fileName) throws Exception {
|
||||
String filePathName = this.baseFrontFolder + File.separator + fileName;
|
||||
final String extention = getExtension(filePathName);
|
||||
String mineType = null;
|
||||
LOGGER.debug("try retrive : '{}' '{}'", filePathName, extention);
|
||||
if (extention.length() != 0 && extention.length() <= 5) {
|
||||
@ -66,26 +66,26 @@ public class FrontGeneric {
|
||||
}
|
||||
} else {
|
||||
mineType = "text/html";
|
||||
filePathName = baseFrontFolder + File.separator + "index.html";
|
||||
filePathName = this.baseFrontFolder + File.separator + "index.html";
|
||||
}
|
||||
LOGGER.debug(" ==> '[}'", filePathName);
|
||||
// reads input image
|
||||
File download = new File(filePathName);
|
||||
final File download = new File(filePathName);
|
||||
if (!download.exists()) {
|
||||
throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'");
|
||||
}
|
||||
ResponseBuilder response = Response.ok((Object) download);
|
||||
final ResponseBuilder response = Response.ok(download);
|
||||
// use this if I want to download the file:
|
||||
//response.header("Content-Disposition", "attachment; filename=" + fileName);
|
||||
CacheControl cc = new CacheControl();
|
||||
final 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)
|
||||
@ -93,15 +93,15 @@ public class FrontGeneric {
|
||||
public Response retrive0() throws Exception {
|
||||
return retrive("index.html");
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("{any: .*}")
|
||||
@PermitAll()
|
||||
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
|
||||
public Response retrive1(@PathParam("any") List<PathSegment> segments) throws Exception {
|
||||
public Response retrive1(@PathParam("any") final List<PathSegment> segments) throws Exception {
|
||||
String filename = "";
|
||||
for (PathSegment elem : segments) {
|
||||
for (final PathSegment elem : segments) {
|
||||
if (!filename.isEmpty()) {
|
||||
filename += File.separator;
|
||||
}
|
||||
|
@ -14,11 +14,11 @@ import jakarta.ws.rs.core.StreamingOutput;
|
||||
public class MediaStreamer implements StreamingOutput {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MediaStreamer.class);
|
||||
private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
|
||||
final byte[] buf = new byte[CHUNK_SIZE];
|
||||
final byte[] buf = new byte[this.CHUNK_SIZE];
|
||||
private long length;
|
||||
private RandomAccessFile raf;
|
||||
|
||||
public MediaStreamer(long length, RandomAccessFile raf) throws IOException {
|
||||
private final RandomAccessFile raf;
|
||||
|
||||
public MediaStreamer(final long length, final RandomAccessFile raf) throws IOException {
|
||||
//logger.info("request stream of {} data", length / 1024);
|
||||
if (length < 0) {
|
||||
throw new IOException("Wrong size of the file to stream: " + length);
|
||||
@ -28,34 +28,34 @@ public class MediaStreamer implements StreamingOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(OutputStream outputStream) {
|
||||
public void write(final OutputStream outputStream) {
|
||||
try {
|
||||
while (length != 0) {
|
||||
int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length);
|
||||
while (this.length != 0) {
|
||||
final int read = this.raf.read(this.buf, 0, this.buf.length > this.length ? (int) this.length : this.buf.length);
|
||||
try {
|
||||
outputStream.write(buf, 0, read);
|
||||
} catch (IOException ex) {
|
||||
outputStream.write(this.buf, 0, read);
|
||||
} catch (final IOException ex) {
|
||||
LOGGER.info("remote close connection");
|
||||
break;
|
||||
}
|
||||
length -= read;
|
||||
this.length -= read;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
} catch (final IOException ex) {
|
||||
throw new InternalServerErrorException(ex);
|
||||
} catch (WebApplicationException ex) {
|
||||
} catch (final WebApplicationException ex) {
|
||||
throw new InternalServerErrorException(ex);
|
||||
} finally {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException ex) {
|
||||
this.raf.close();
|
||||
} catch (final IOException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new InternalServerErrorException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public long getLenth() {
|
||||
return length;
|
||||
return this.length;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -623,7 +623,7 @@ public class DataAccess {
|
||||
// check the compatibility of the id and the declared ID
|
||||
final Class<?> typeClass = idField.getType();
|
||||
if (id == typeClass) {
|
||||
throw new Exception("Request update with the wriong type ...");
|
||||
throw new Exception("Request update with the wrong type ...");
|
||||
}
|
||||
// Udpade Json Value
|
||||
return updateWithJson(clazz, new QueryCondition(AnnotationTools.getFieldName(idField), "=", id), jsonData);
|
||||
@ -638,15 +638,15 @@ public class DataAccess {
|
||||
final List<String> keys = new ArrayList<>();
|
||||
final var iterator = root.fieldNames();
|
||||
iterator.forEachRemaining(e -> keys.add(e));
|
||||
return update(data, condition, keys);
|
||||
return updateWhere(data, condition, null, keys);
|
||||
}
|
||||
|
||||
public static <T, ID_TYPE> int update(final T data, final ID_TYPE id) throws Exception {
|
||||
return update(data, id, null);
|
||||
}
|
||||
|
||||
public static <T> int update(final T data, final QueryItem condition) throws Exception {
|
||||
return update(data, condition, null);
|
||||
public static <T> int updateWhere(final T data, final QueryItem condition) throws Exception {
|
||||
return updateWhere(data, condition, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,10 +10,7 @@ import java.util.Map.Entry;
|
||||
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey/45814178#45814178
|
||||
// https://stackoverflow.com/questions/32817210/how-to-access-jersey-resource-secured-by-rolesallowed
|
||||
|
||||
import org.kar.archidata.annotation.security.DenyAll;
|
||||
import org.kar.archidata.annotation.security.PermitAll;
|
||||
import org.kar.archidata.annotation.security.PermitTokenInURI;
|
||||
import org.kar.archidata.annotation.security.RolesAllowed;
|
||||
import org.kar.archidata.catcher.RestErrorResponse;
|
||||
import org.kar.archidata.model.UserByToken;
|
||||
import org.kar.archidata.util.JWTWrapper;
|
||||
@ -23,6 +20,9 @@ import org.slf4j.LoggerFactory;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.annotation.security.DenyAll;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.ws.rs.Priorities;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
@ -42,31 +42,30 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
@Context
|
||||
private ResourceInfo resourceInfo;
|
||||
protected final String applicationName;
|
||||
|
||||
|
||||
private static final String AUTHENTICATION_SCHEME = "Yota";
|
||||
private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota";
|
||||
|
||||
public AuthenticationFilter(String applicationName) {
|
||||
super();
|
||||
|
||||
public AuthenticationFilter(final String applicationName) {
|
||||
this.applicationName = applicationName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
public void filter(final ContainerRequestContext requestContext) throws IOException {
|
||||
/*
|
||||
logger.debug("-----------------------------------------------------");
|
||||
logger.debug("---- Check if have authorization ----");
|
||||
logger.debug("-----------------------------------------------------");
|
||||
logger.debug(" for:{}", requestContext.getUriInfo().getPath());
|
||||
*/
|
||||
Method method = resourceInfo.getResourceMethod();
|
||||
final Method method = this.resourceInfo.getResourceMethod();
|
||||
// Access denied for all
|
||||
if (method.isAnnotationPresent(DenyAll.class)) {
|
||||
logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
|
||||
this.logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
|
||||
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Access allowed for all
|
||||
if (method.isAnnotationPresent(PermitAll.class)) {
|
||||
//logger.debug(" ==> permit all " + requestContext.getUriInfo().getPath());
|
||||
@ -75,17 +74,17 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
}
|
||||
// this is a security guard, all the API must define their access level:
|
||||
if (!method.isAnnotationPresent(RolesAllowed.class)) {
|
||||
logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
|
||||
this.logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
|
||||
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get the Authorization header from the request
|
||||
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
|
||||
//logger.debug("authorizationHeader: {}", authorizationHeader);
|
||||
if (authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) {
|
||||
MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
|
||||
for (Entry<String, List<String>> item : quaryparam.entrySet()) {
|
||||
final MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
|
||||
for (final Entry<String, List<String>> item : quaryparam.entrySet()) {
|
||||
if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) {
|
||||
if (!item.getValue().isEmpty()) {
|
||||
authorizationHeader = item.getValue().get(0);
|
||||
@ -95,58 +94,58 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
}
|
||||
}
|
||||
// logger.debug("authorizationHeader: {}", authorizationHeader);
|
||||
boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
|
||||
boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
|
||||
final boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
|
||||
final boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
|
||||
// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)"
|
||||
if (!isApplicationToken && !isJwtToken) {
|
||||
logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
|
||||
this.logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
|
||||
abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath());
|
||||
return;
|
||||
}
|
||||
UserByToken userByToken = null;
|
||||
if (isJwtToken) {
|
||||
// Extract the token from the Authorization header (Remove "Yota ")
|
||||
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
|
||||
final String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
|
||||
//logger.debug("token: {}", token);
|
||||
try {
|
||||
userByToken = validateJwtToken(token);
|
||||
} catch (Exception e) {
|
||||
logger.error("Fail to validate token: {}", e.getMessage());
|
||||
} catch (final Exception e) {
|
||||
this.logger.error("Fail to validate token: {}", e.getMessage());
|
||||
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
if (userByToken == null) {
|
||||
logger.warn("get a NULL user ...");
|
||||
this.logger.warn("get a NULL user ...");
|
||||
abortWithUnauthorized(requestContext, "get a NULL user ...");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Extract the token from the Authorization header (Remove "Zota ")
|
||||
String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
|
||||
final String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
|
||||
//logger.debug("token: {}", token);
|
||||
try {
|
||||
userByToken = validateToken(token);
|
||||
} catch (Exception e) {
|
||||
logger.error("Fail to validate token: {}", e.getMessage());
|
||||
} catch (final Exception e) {
|
||||
this.logger.error("Fail to validate token: {}", e.getMessage());
|
||||
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
if (userByToken == null) {
|
||||
logger.warn("get a NULL application ...");
|
||||
this.logger.warn("get a NULL application ...");
|
||||
abortWithUnauthorized(requestContext, "get a NULL application ...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// create the security context model:
|
||||
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
|
||||
MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
|
||||
final String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
|
||||
final MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
|
||||
// retrieve the allowed right:
|
||||
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
|
||||
List<String> roles = Arrays.asList(rolesAnnotation.value());
|
||||
final RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
|
||||
final List<String> roles = Arrays.asList(rolesAnnotation.value());
|
||||
// check if the user have the right:
|
||||
boolean haveRight = false;
|
||||
for (String role : roles) {
|
||||
for (final String role : roles) {
|
||||
if (userContext.isUserInRole(role)) {
|
||||
haveRight = true;
|
||||
break;
|
||||
@ -154,67 +153,67 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
}
|
||||
//Is user valid?
|
||||
if (!haveRight) {
|
||||
logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
|
||||
this.logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
|
||||
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build());
|
||||
return;
|
||||
}
|
||||
requestContext.setSecurityContext(userContext);
|
||||
// logger.debug("Get local user : {} / {}", user, userByToken);
|
||||
}
|
||||
|
||||
private boolean isTokenBasedAuthentication(String authorizationHeader) {
|
||||
|
||||
private boolean isTokenBasedAuthentication(final String authorizationHeader) {
|
||||
// Check if the Authorization header is valid
|
||||
// It must not be null and must be prefixed with "Bearer" plus a whitespace
|
||||
// The authentication scheme comparison must be case-insensitive
|
||||
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " ");
|
||||
}
|
||||
|
||||
private boolean isApplicationTokenBasedAuthentication(String authorizationHeader) {
|
||||
|
||||
private boolean isApplicationTokenBasedAuthentication(final String authorizationHeader) {
|
||||
// Check if the Authorization header is valid
|
||||
// It must not be null and must be prefixed with "Bearer" plus a whitespace
|
||||
// The authentication scheme comparison must be case-insensitive
|
||||
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " ");
|
||||
}
|
||||
|
||||
private void abortWithUnauthorized(ContainerRequestContext requestContext, String message) {
|
||||
|
||||
|
||||
private void abortWithUnauthorized(final ContainerRequestContext requestContext, final String message) {
|
||||
|
||||
// Abort the filter chain with a 401 status code response
|
||||
// The WWW-Authenticate header is sent along with the response
|
||||
logger.warn("abortWithUnauthorized:");
|
||||
RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
|
||||
logger.error("Error UUID={}", ret.uuid);
|
||||
this.logger.warn("abortWithUnauthorized:");
|
||||
final RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
|
||||
this.logger.error("Error UUID={}", ret.uuid);
|
||||
requestContext.abortWith(Response.status(ret.status).header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)").entity(ret)
|
||||
.type(MediaType.APPLICATION_JSON).build());
|
||||
}
|
||||
|
||||
protected UserByToken validateToken(String authorization) throws Exception {
|
||||
logger.info("Must be Override by the application implmentation, otherwise it dose not work");
|
||||
|
||||
protected UserByToken validateToken(final String authorization) throws Exception {
|
||||
this.logger.info("Must be Override by the application implmentation, otherwise it dose not work");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// must be override to be good implementation
|
||||
protected UserByToken validateJwtToken(String authorization) throws Exception {
|
||||
protected UserByToken validateJwtToken(final String authorization) throws Exception {
|
||||
//logger.debug(" validate token : " + authorization);
|
||||
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
|
||||
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
|
||||
// check the token is valid !!! (signed and coherent issuer...
|
||||
if (ret == null) {
|
||||
logger.error("The token is not valid: '{}'", authorization);
|
||||
this.logger.error("The token is not valid: '{}'", authorization);
|
||||
return null;
|
||||
}
|
||||
// check userID
|
||||
String userUID = ret.getSubject();
|
||||
long id = Long.parseLong(userUID);
|
||||
UserByToken user = new UserByToken();
|
||||
final String userUID = ret.getSubject();
|
||||
final long id = Long.parseLong(userUID);
|
||||
final UserByToken user = new UserByToken();
|
||||
user.id = id;
|
||||
user.name = (String) ret.getClaim("login");
|
||||
user.type = UserByToken.TYPE_USER;
|
||||
Object rowRight = ret.getClaim("right");
|
||||
final Object rowRight = ret.getClaim("right");
|
||||
if (rowRight != null) {
|
||||
Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
|
||||
final Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
|
||||
if (rights.containsKey(this.applicationName)) {
|
||||
user.right = rights.get(this.applicationName);
|
||||
} else {
|
||||
logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
|
||||
this.logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
|
||||
}
|
||||
}
|
||||
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight);
|
||||
|
@ -4,6 +4,4 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record GetToken(
|
||||
String jwt) {
|
||||
|
||||
}
|
||||
String jwt) {}
|
||||
|
@ -13,7 +13,8 @@ public class ConfigBaseVariable {
|
||||
static public String apiAdress;
|
||||
static public String ssoAdress;
|
||||
static public String ssoToken;
|
||||
|
||||
static public String testMode;
|
||||
|
||||
// For test only
|
||||
public static void clearAllValue() {
|
||||
tmpDataFolder = System.getenv("DATA_TMP_FOLDER");
|
||||
@ -28,82 +29,83 @@ public class ConfigBaseVariable {
|
||||
apiAdress = System.getenv("API_ADDRESS");
|
||||
ssoAdress = System.getenv("SSO_ADDRESS");
|
||||
ssoToken = System.getenv("SSO_TOKEN");
|
||||
testMode = System.getenv("TEST_MODE");
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
clearAllValue();
|
||||
}
|
||||
|
||||
|
||||
public static String getTmpDataFolder() {
|
||||
if (tmpDataFolder == null) {
|
||||
return "/application/data/tmp";
|
||||
}
|
||||
return tmpDataFolder;
|
||||
}
|
||||
|
||||
|
||||
public static String getMediaDataFolder() {
|
||||
if (dataFolder == null) {
|
||||
return "/application/data/media";
|
||||
}
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
|
||||
public static String getDBType() {
|
||||
if (dbType == null) {
|
||||
return "mysql";
|
||||
}
|
||||
return dbType;
|
||||
}
|
||||
|
||||
|
||||
public static String getDBHost() {
|
||||
if (dbHost == null) {
|
||||
return "localhost";
|
||||
}
|
||||
return dbHost;
|
||||
}
|
||||
|
||||
|
||||
public static String getDBPort() {
|
||||
if (dbPort == null) {
|
||||
return "3306";
|
||||
}
|
||||
return dbPort;
|
||||
}
|
||||
|
||||
|
||||
public static String getDBLogin() {
|
||||
if (dbUser == null) {
|
||||
return "root";
|
||||
}
|
||||
return dbUser;
|
||||
}
|
||||
|
||||
|
||||
public static String getDBPassword() {
|
||||
if (dbPassword == null) {
|
||||
return "base_db_password";
|
||||
}
|
||||
return dbPassword;
|
||||
}
|
||||
|
||||
|
||||
public static String getDBName() {
|
||||
if (bdDatabase == null) {
|
||||
return "unknown";
|
||||
}
|
||||
return bdDatabase;
|
||||
}
|
||||
|
||||
|
||||
public static boolean getDBKeepConnected() {
|
||||
if (dbKeepConnected == null) {
|
||||
return false;
|
||||
}
|
||||
return Boolean.parseBoolean(dbKeepConnected);
|
||||
}
|
||||
|
||||
|
||||
public static String getlocalAddress() {
|
||||
if (apiAdress == null) {
|
||||
return "http://0.0.0.0:80/api/";
|
||||
}
|
||||
return apiAdress;
|
||||
}
|
||||
|
||||
|
||||
public static String getSSOAddress() {
|
||||
return ssoAdress;
|
||||
}
|
||||
@ -111,4 +113,11 @@ public class ConfigBaseVariable {
|
||||
public static String ssoToken() {
|
||||
return ssoToken;
|
||||
}
|
||||
|
||||
public static boolean getTestMode() {
|
||||
if (testMode == null) {
|
||||
return false;
|
||||
}
|
||||
return Boolean.parseBoolean(testMode);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -18,108 +19,148 @@ import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JOSEObjectType;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.JWSObject;
|
||||
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.jca.JCAContext;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
|
||||
import com.nimbusds.jose.util.Base64URL;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
public class JWTWrapper {
|
||||
static final Logger logger = LoggerFactory.getLogger(JWTWrapper.class);
|
||||
class TestSigner implements JWSSigner {
|
||||
public static String test_signature = "TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E";
|
||||
|
||||
/**
|
||||
* Signs the specified {@link JWSObject#getSigningInput input} of a
|
||||
* {@link JWSObject JWS object}.
|
||||
*
|
||||
* @param header The JSON Web Signature (JWS) header. Must
|
||||
* specify a supported JWS algorithm and must not
|
||||
* be {@code null}.
|
||||
* @param signingInput The input to sign. Must not be {@code null}.
|
||||
*
|
||||
* @return The resulting signature part (third part) of the JWS object.
|
||||
*
|
||||
* @throws JOSEException If the JWS algorithm is not supported, if a
|
||||
* critical header parameter is not supported or
|
||||
* marked for deferral to the application, or if
|
||||
* signing failed for some other internal reason.
|
||||
*/
|
||||
@Override
|
||||
public Base64URL sign(final JWSHeader header, final byte[] signingInput) throws JOSEException {
|
||||
return new Base64URL(test_signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<JWSAlgorithm> supportedJWSAlgorithms() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JCAContext getJCAContext() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class JWTWrapper {
|
||||
static final Logger LOGGER = LoggerFactory.getLogger(JWTWrapper.class);
|
||||
|
||||
private static RSAKey rsaJWK = null;;
|
||||
private static RSAKey rsaPublicJWK = null;
|
||||
|
||||
|
||||
public static class PublicKey {
|
||||
public String key;
|
||||
|
||||
public PublicKey(String key) {
|
||||
|
||||
public PublicKey(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
|
||||
public PublicKey() {}
|
||||
}
|
||||
|
||||
public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException {
|
||||
|
||||
public static void initLocalTokenRemote(final String ssoUri, final String application) throws IOException, ParseException {
|
||||
// check Token:
|
||||
URL obj = new URL(ssoUri + "public_key");
|
||||
//logger.debug("Request token from: {}", obj);
|
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
final URL obj = new URL(ssoUri + "public_key");
|
||||
//LOGGER.debug("Request token from: {}", obj);
|
||||
final HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
con.setRequestProperty("User-Agent", application);
|
||||
con.setRequestProperty("Cache-Control", "no-cache");
|
||||
con.setRequestProperty("Content-Type", "application/json");
|
||||
con.setRequestProperty("Accept", "application/json");
|
||||
String ssoToken = ConfigBaseVariable.ssoToken();
|
||||
final String ssoToken = ConfigBaseVariable.ssoToken();
|
||||
if (ssoToken != null) {
|
||||
con.setRequestProperty("Authorization", "Zota " + ssoToken);
|
||||
}
|
||||
int responseCode = con.getResponseCode();
|
||||
|
||||
//logger.debug("GET Response Code :: {}", responseCode);
|
||||
final int responseCode = con.getResponseCode();
|
||||
|
||||
//LOGGER.debug("GET Response Code :: {}", responseCode);
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) { // success
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
|
||||
final BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
|
||||
String inputLine;
|
||||
StringBuffer response = new StringBuffer();
|
||||
final StringBuffer response = new StringBuffer();
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
// print result
|
||||
//logger.debug(response.toString());
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
|
||||
//LOGGER.debug(response.toString());
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
|
||||
rsaPublicJWK = RSAKey.parse(values.key);
|
||||
return;
|
||||
}
|
||||
logger.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj);
|
||||
LOGGER.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj);
|
||||
}
|
||||
|
||||
public static void initLocalToken(String baseUUID) throws Exception {
|
||||
// RSA signatures require a public and private RSA key pair, the public key
|
||||
|
||||
public static void initLocalToken(final String baseUUID) throws Exception {
|
||||
// RSA signatures require a public and private RSA key pair, the public key
|
||||
// must be made known to the JWS recipient in order to verify the signatures
|
||||
try {
|
||||
String generatedStringForKey = baseUUID;
|
||||
if (generatedStringForKey == null) {
|
||||
logger.error(" Generate new UUID : {}", generatedStringForKey);
|
||||
LOGGER.error(" Generate new UUID : {}", generatedStringForKey);
|
||||
generatedStringForKey = UUID.randomUUID().toString();
|
||||
} else {
|
||||
logger.error("USE UUID : {}", generatedStringForKey);
|
||||
LOGGER.error("USE UUID : {}", generatedStringForKey);
|
||||
}
|
||||
rsaJWK = new RSAKeyGenerator(2048).keyID(generatedStringForKey).generate();
|
||||
rsaPublicJWK = rsaJWK.toPublicJWK();
|
||||
logger.error("RSA key (all): " + rsaJWK.toJSONString());
|
||||
logger.error("RSA key (pub): " + rsaPublicJWK.toJSONString());
|
||||
} catch (JOSEException e) {
|
||||
LOGGER.error("RSA key (all): " + rsaJWK.toJSONString());
|
||||
LOGGER.error("RSA key (pub): " + rsaPublicJWK.toJSONString());
|
||||
} catch (final JOSEException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
logger.debug("Can not generate teh public abnd private keys ...");
|
||||
LOGGER.debug("Can not generate teh public abnd private keys ...");
|
||||
rsaJWK = null;
|
||||
rsaPublicJWK = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void initValidateToken(String publicKey) {
|
||||
|
||||
public static void initValidateToken(final String publicKey) {
|
||||
try {
|
||||
rsaPublicJWK = RSAKey.parse(publicKey);
|
||||
} catch (ParseException e) {
|
||||
} catch (final ParseException e) {
|
||||
e.printStackTrace();
|
||||
logger.debug("Can not retrieve public Key !!!!!!!! RSAKey='{}'", publicKey);
|
||||
LOGGER.debug("Can not retrieve public Key !!!!!!!! RSAKey='{}'", publicKey);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static String getPublicKeyJson() {
|
||||
if (rsaPublicJWK == null) {
|
||||
return null;
|
||||
}
|
||||
return rsaPublicJWK.toJSONString();
|
||||
}
|
||||
|
||||
|
||||
public static java.security.interfaces.RSAPublicKey getPublicKeyJava() throws JOSEException {
|
||||
if (rsaPublicJWK == null) {
|
||||
return null;
|
||||
@ -127,7 +168,7 @@ public class JWTWrapper {
|
||||
// Convert back to std Java interface
|
||||
return rsaPublicJWK.toRSAPublicKey();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a token with the provided elements
|
||||
* @param userID UniqueId of the USER (global unique ID)
|
||||
@ -136,81 +177,122 @@ public class JWTWrapper {
|
||||
* @param timeOutInMunites Expiration of the token.
|
||||
* @return the encoded token
|
||||
*/
|
||||
public static String generateJWToken(long userID, String userLogin, String isuer, String application, Map<String, Object> rights, int timeOutInMunites) {
|
||||
public static String generateJWToken(final long userID, final String userLogin, final String isuer, final String application, final Map<String, Object> rights, final int timeOutInMunites) {
|
||||
if (rsaJWK == null) {
|
||||
logger.warn("JWT private key is not present !!!");
|
||||
LOGGER.warn("JWT private key is not present !!!");
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
logger.debug(" ===> expire in : " + timeOutInMunites);
|
||||
logger.debug(" ===>" + new Date().getTime());
|
||||
logger.debug(" ===>" + new Date(new Date().getTime()));
|
||||
logger.debug(" ===>" + new Date(new Date().getTime() - 60 * timeOutInMunites * 1000));
|
||||
LOGGER.debug(" ===> expire in : " + timeOutInMunites);
|
||||
LOGGER.debug(" ===>" + new Date().getTime());
|
||||
LOGGER.debug(" ===>" + new Date(new Date().getTime()));
|
||||
LOGGER.debug(" ===>" + new Date(new Date().getTime() - 60 * timeOutInMunites * 1000));
|
||||
*/
|
||||
try {
|
||||
// Create RSA-signer with the private key
|
||||
JWSSigner signer = new RSASSASigner(rsaJWK);
|
||||
|
||||
logger.warn("timeOutInMunites= {}", timeOutInMunites);
|
||||
Date now = new Date();
|
||||
logger.warn("now = {}", now);
|
||||
Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
|
||||
|
||||
logger.warn("expiration= {}", expiration);
|
||||
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
|
||||
final JWSSigner signer = new RSASSASigner(rsaJWK);
|
||||
|
||||
LOGGER.warn("timeOutInMunites= {}", timeOutInMunites);
|
||||
final Date now = new Date();
|
||||
LOGGER.warn("now = {}", now);
|
||||
final Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
|
||||
|
||||
LOGGER.warn("expiration= {}", expiration);
|
||||
final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
|
||||
.expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning
|
||||
// add right if needed:
|
||||
if (rights != null && !rights.isEmpty()) {
|
||||
builder.claim("right", rights);
|
||||
}
|
||||
// Prepare JWT with claims set
|
||||
JWTClaimsSet claimsSet = builder.build();
|
||||
SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
|
||||
|
||||
final JWTClaimsSet claimsSet = builder.build();
|
||||
final 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) {
|
||||
} catch (final JOSEException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JWTClaimsSet validateToken(String signedToken, String isuer, String application) {
|
||||
if (rsaPublicJWK == null) {
|
||||
logger.warn("JWT public key is not present !!!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JWTClaimsSet validateToken(final String signedToken, final String isuer, final String application) {
|
||||
try {
|
||||
// On the consumer side, parse the JWS and verify its RSA signature
|
||||
SignedJWT signedJWT = SignedJWT.parse(signedToken);
|
||||
final SignedJWT signedJWT = SignedJWT.parse(signedToken);
|
||||
|
||||
JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
|
||||
if (!signedJWT.verify(verifier)) {
|
||||
logger.error("JWT token is NOT verified ");
|
||||
return null;
|
||||
if (rsaPublicJWK == null) {
|
||||
LOGGER.warn("JWT public key is not present !!!");
|
||||
if (!ConfigBaseVariable.getTestMode()) {
|
||||
return null;
|
||||
}
|
||||
final String rawSignature = signedJWT.getSigningInput().toString();
|
||||
if (rawSignature.equals(TestSigner.test_signature)) {
|
||||
// Test token : .application..
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
final JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
|
||||
if (!signedJWT.verify(verifier)) {
|
||||
LOGGER.error("JWT token is NOT verified ");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime())) {
|
||||
logger.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime());
|
||||
LOGGER.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime());
|
||||
return null;
|
||||
}
|
||||
if (!isuer.equals(signedJWT.getJWTClaimsSet().getIssuer())) {
|
||||
logger.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
|
||||
LOGGER.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
|
||||
return null;
|
||||
}
|
||||
if (application != null) {
|
||||
// TODO: verify the token is used for the correct application.
|
||||
}
|
||||
// the element must be validated outside ...
|
||||
//logger.debug("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'");
|
||||
//logger.debug("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
|
||||
//LOGGER.debug("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'");
|
||||
//LOGGER.debug("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
|
||||
return signedJWT.getJWTClaimsSet();
|
||||
} catch (JOSEException ex) {
|
||||
} catch (final JOSEException ex) {
|
||||
ex.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
} catch (final ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String createJwtTestToken(final long userID, final String userLogin, final String isuer, final String application, final Map<String, Object> rights) {
|
||||
if (!ConfigBaseVariable.getTestMode()) {
|
||||
LOGGER.error("Test mode disable !!!!!");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final int timeOutInMunites = 3600 * 24 * 31;
|
||||
|
||||
final Date now = new Date();
|
||||
final Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
|
||||
|
||||
final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
|
||||
.expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning
|
||||
// add right if needed:
|
||||
if (rights != null && !rights.isEmpty()) {
|
||||
builder.claim("right", rights);
|
||||
}
|
||||
// Prepare JWT with claims set
|
||||
final JWTClaimsSet claimsSet = builder.build();
|
||||
final SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
|
||||
|
||||
// Compute the RSA signature
|
||||
signedJWT.sign(new TestSigner());
|
||||
|
||||
// serialize the output...
|
||||
return signedJWT.serialize();
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Can not generate Test Token...");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ public class TestTypes {
|
||||
Assertions.assertEquals(insertedData.id, retrieve.id);
|
||||
Assertions.assertNotNull(retrieve.doubleData);
|
||||
Assertions.assertEquals(insertedData.doubleData, retrieve.doubleData);
|
||||
|
||||
|
||||
DataAccess.delete(TypesTable.class, insertedData.id);
|
||||
}
|
||||
|
||||
@ -347,4 +347,123 @@ public class TestTypes {
|
||||
|
||||
DataAccess.delete(TypesTable.class, insertedData.id);
|
||||
}
|
||||
|
||||
@Order(14)
|
||||
@Test
|
||||
public void testTextUpdateDirect() throws Exception {
|
||||
|
||||
final TypesTable test = new TypesTable();
|
||||
test.textData = "test 1";
|
||||
test.booleanData = null;
|
||||
test.varcharData = "plop";
|
||||
final TypesTable insertedData = DataAccess.insert(test);
|
||||
Assertions.assertNotNull(insertedData);
|
||||
Assertions.assertNotNull(insertedData.id);
|
||||
Assertions.assertTrue(insertedData.id >= 0);
|
||||
|
||||
// Try to retrieve all the data:
|
||||
final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id);
|
||||
|
||||
Assertions.assertNotNull(retrieve);
|
||||
Assertions.assertNotNull(retrieve.id);
|
||||
Assertions.assertEquals(insertedData.id, retrieve.id);
|
||||
Assertions.assertNotNull(retrieve.textData);
|
||||
Assertions.assertEquals(insertedData.textData, retrieve.textData);
|
||||
Assertions.assertNull(retrieve.booleanData);
|
||||
Assertions.assertNotNull(retrieve.varcharData);
|
||||
Assertions.assertEquals(insertedData.varcharData, retrieve.varcharData);
|
||||
|
||||
// Update the text value:
|
||||
retrieve.textData = "test 2";
|
||||
retrieve.booleanData = true;
|
||||
retrieve.varcharData = null;
|
||||
final int nbUpdate = DataAccess.update(retrieve, insertedData.id);
|
||||
Assertions.assertEquals(1, nbUpdate);
|
||||
|
||||
// Get new data
|
||||
final TypesTable retrieve2 = DataAccess.get(TypesTable.class, insertedData.id);
|
||||
|
||||
Assertions.assertNotNull(retrieve2);
|
||||
Assertions.assertNotNull(retrieve2.id);
|
||||
Assertions.assertEquals(insertedData.id, retrieve2.id);
|
||||
Assertions.assertNotNull(retrieve2.textData);
|
||||
Assertions.assertEquals(retrieve.textData, retrieve2.textData);
|
||||
Assertions.assertNotNull(retrieve2.booleanData);
|
||||
Assertions.assertEquals(retrieve.booleanData, retrieve2.booleanData);
|
||||
Assertions.assertNull(retrieve2.varcharData);
|
||||
|
||||
// test filter values:
|
||||
retrieve.textData = "test 3";
|
||||
retrieve.booleanData = false;
|
||||
retrieve.varcharData = "test3";
|
||||
final int nbUpdate2 = DataAccess.update(retrieve, insertedData.id, List.of("textData"));
|
||||
Assertions.assertEquals(1, nbUpdate2);
|
||||
|
||||
// Get new data
|
||||
final TypesTable retrieve3 = DataAccess.get(TypesTable.class, insertedData.id);
|
||||
|
||||
Assertions.assertNotNull(retrieve3);
|
||||
Assertions.assertNotNull(retrieve3.id);
|
||||
Assertions.assertEquals(insertedData.id, retrieve3.id);
|
||||
Assertions.assertNotNull(retrieve3.textData);
|
||||
Assertions.assertEquals(retrieve.textData, retrieve3.textData);
|
||||
Assertions.assertNotNull(retrieve3.booleanData);
|
||||
// note: retreive2
|
||||
Assertions.assertEquals(retrieve2.booleanData, retrieve3.booleanData);
|
||||
Assertions.assertNull(retrieve3.varcharData);
|
||||
|
||||
DataAccess.delete(TypesTable.class, insertedData.id);
|
||||
}
|
||||
|
||||
@Order(15)
|
||||
@Test
|
||||
public void testTextUpdateJson() throws Exception {
|
||||
|
||||
final TypesTable test = new TypesTable();
|
||||
test.textData = "test 1";
|
||||
test.booleanData = null;
|
||||
test.varcharData = "plop";
|
||||
final TypesTable insertedData = DataAccess.insert(test);
|
||||
Assertions.assertNotNull(insertedData);
|
||||
Assertions.assertNotNull(insertedData.id);
|
||||
Assertions.assertTrue(insertedData.id >= 0);
|
||||
|
||||
// Try to retrieve all the data:
|
||||
final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id);
|
||||
|
||||
Assertions.assertNotNull(retrieve);
|
||||
Assertions.assertNotNull(retrieve.id);
|
||||
Assertions.assertEquals(insertedData.id, retrieve.id);
|
||||
Assertions.assertNotNull(retrieve.textData);
|
||||
Assertions.assertEquals(insertedData.textData, retrieve.textData);
|
||||
Assertions.assertNull(retrieve.booleanData);
|
||||
Assertions.assertNotNull(retrieve.varcharData);
|
||||
Assertions.assertEquals(insertedData.varcharData, retrieve.varcharData);
|
||||
|
||||
// Update the text value:
|
||||
final String jsonData = """
|
||||
{
|
||||
"textData": "test 2",
|
||||
"booleanData": true,
|
||||
"varcharData": null
|
||||
}
|
||||
""";
|
||||
final int nbUpdate = DataAccess.updateWithJson(TypesTable.class, insertedData.id, jsonData);
|
||||
Assertions.assertEquals(1, nbUpdate);
|
||||
|
||||
// Get new data
|
||||
final TypesTable retrieve2 = DataAccess.get(TypesTable.class, insertedData.id);
|
||||
|
||||
Assertions.assertNotNull(retrieve2);
|
||||
Assertions.assertNotNull(retrieve2.id);
|
||||
Assertions.assertEquals(insertedData.id, retrieve2.id);
|
||||
Assertions.assertNotNull(retrieve2.textData);
|
||||
Assertions.assertEquals(retrieve.textData, retrieve2.textData);
|
||||
Assertions.assertNotNull(retrieve2.booleanData);
|
||||
Assertions.assertEquals(retrieve.booleanData, retrieve2.booleanData);
|
||||
Assertions.assertNull(retrieve2.varcharData);
|
||||
|
||||
DataAccess.delete(TypesTable.class, insertedData.id);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user