diff --git a/pom.xml b/pom.xml
index 42c091f..f6408b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
kangaroo-and-rabbit
archidata
- 0.5.0
+ 0.5.1
3.1
21
diff --git a/src/org/kar/archidata/dataAccess/DataAccess.java b/src/org/kar/archidata/dataAccess/DataAccess.java
index 8e6d6e6..cd80caa 100644
--- a/src/org/kar/archidata/dataAccess/DataAccess.java
+++ b/src/org/kar/archidata/dataAccess/DataAccess.java
@@ -480,7 +480,7 @@ public class DataAccess {
if (options != null) {
final CheckFunction check = options.get(CheckFunction.class);
if (check != null) {
- check.getChecker().check(data, null);
+ check.getChecker().check(data, AnnotationTools.getFieldsNames(clazz));
}
}
@@ -655,11 +655,11 @@ public class DataAccess {
* @param jsonData Json data (partial) values to update
* @return the number of object updated
* @throws Exception */
- public static int updateWithJson(final Class clazz, final ID_TYPE id, final String jsonData) throws Exception {
- return updateWhereWithJson(clazz, getTableIdCondition(clazz, id), jsonData);
+ public static int updateWithJson(final Class clazz, final ID_TYPE id, final String jsonData, final QueryOptions options) throws Exception {
+ return updateWhereWithJson(clazz, getTableIdCondition(clazz, id), jsonData, options);
}
- public static int updateWhereWithJson(final Class clazz, final QueryItem condition, final String jsonData) throws Exception {
+ public static int updateWhereWithJson(final Class clazz, final QueryItem condition, final String jsonData, final QueryOptions options) throws Exception {
final ObjectMapper mapper = new ObjectMapper();
// parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz);
@@ -668,7 +668,8 @@ public class DataAccess {
final List keys = new ArrayList<>();
final var iterator = root.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
- return updateWhere(data, condition, null, keys);
+ // TODO: set the filter in the Options...
+ return updateWhere(data, condition, options, keys);
}
public static int update(final T data, final ID_TYPE id) throws Exception {
diff --git a/src/org/kar/archidata/filter/AuthenticationFilter.java b/src/org/kar/archidata/filter/AuthenticationFilter.java
index c2b97c0..7582de5 100644
--- a/src/org/kar/archidata/filter/AuthenticationFilter.java
+++ b/src/org/kar/archidata/filter/AuthenticationFilter.java
@@ -38,7 +38,7 @@ import jakarta.ws.rs.ext.Provider;
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
- final Logger logger = LoggerFactory.getLogger(AuthenticationFilter.class);
+ private final static Logger LOGGER = LoggerFactory.getLogger(AuthenticationFilter.class);
@Context
private ResourceInfo resourceInfo;
protected final String applicationName;
@@ -57,7 +57,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
final Method method = this.resourceInfo.getResourceMethod();
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
- this.logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
+ LOGGER.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build());
return;
}
@@ -70,7 +70,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
// this is a security guard, all the API must define their access level:
if (!method.isAnnotationPresent(RolesAllowed.class)) {
- this.logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
+ LOGGER.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build());
return;
}
@@ -94,7 +94,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
final boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)"
if (!isApplicationToken && !isJwtToken) {
- this.logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
+ LOGGER.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath());
return;
}
@@ -106,12 +106,12 @@ public class AuthenticationFilter implements ContainerRequestFilter {
try {
userByToken = validateJwtToken(token);
} catch (final Exception e) {
- this.logger.error("Fail to validate token: {}", e.getMessage());
+ LOGGER.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
- this.logger.warn("get a NULL user ...");
+ LOGGER.warn("get a NULL user ...");
abortWithUnauthorized(requestContext, "get a NULL user ...");
return;
}
@@ -122,12 +122,12 @@ public class AuthenticationFilter implements ContainerRequestFilter {
try {
userByToken = validateToken(token);
} catch (final Exception e) {
- this.logger.error("Fail to validate token: {}", e.getMessage());
+ LOGGER.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
- this.logger.warn("get a NULL application ...");
+ LOGGER.warn("get a NULL application ...");
abortWithUnauthorized(requestContext, "get a NULL application ...");
return;
}
@@ -149,7 +149,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
// Is user valid?
if (!haveRight) {
- this.logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
+ LOGGER.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build());
return;
}
@@ -175,15 +175,15 @@ public class AuthenticationFilter implements ContainerRequestFilter {
// Abort the filter chain with a 401 status code response
// The WWW-Authenticate header is sent along with the response
- this.logger.warn("abortWithUnauthorized:");
+ LOGGER.warn("abortWithUnauthorized:");
final RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
- this.logger.error("Error UUID={}", ret.uuid);
+ 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(final String authorization) throws Exception {
- this.logger.info("Must be Override by the application implmentation, otherwise it dose not work");
+ LOGGER.info("Must be Override by the application implmentation, otherwise it dose not work");
return null;
}
@@ -193,7 +193,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
if (ret == null) {
- this.logger.error("The token is not valid: '{}'", authorization);
+ LOGGER.error("The token is not valid: '{}'", authorization);
return null;
}
// check userID
@@ -209,7 +209,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
if (rights.containsKey(this.applicationName)) {
user.right = rights.get(this.applicationName);
} else {
- this.logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
+ LOGGER.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
}
}
// logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight);
diff --git a/src/org/kar/archidata/migration/model/Migration1.java b/src/org/kar/archidata/migration/model/Migration1.java
new file mode 100644
index 0000000..17d5092
--- /dev/null
+++ b/src/org/kar/archidata/migration/model/Migration1.java
@@ -0,0 +1,35 @@
+package org.kar.archidata.migration.model;
+
+import org.kar.archidata.annotation.DataComment;
+import org.kar.archidata.annotation.DataDefault;
+import org.kar.archidata.annotation.DataIfNotExists;
+import org.kar.archidata.model.GenericDataSoftDelete;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Table;
+
+// For logs only
+//public static final String TABLE_NAME = "KAR_migration";
+
+@Table(name = "KAR_migration")
+@DataIfNotExists
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class Migration1 extends GenericDataSoftDelete {
+ final static int VERSION_MIGRATION = 1;
+ @DataComment("Name of the migration")
+ @Column(length = 256)
+ public String name;
+ @Column(nullable = false)
+ @DataDefault("'0'")
+ @DataComment("if the migration is well terminated or not")
+ public Boolean terminated = false;
+ @DataComment("index in the migration progression")
+ public Integer stepId = 0;
+ @DataComment("number of element in the migration")
+ public Integer count;
+ @DataComment("Log generate by the migration")
+ @Column(length = 0)
+ public String log = "";
+}
diff --git a/src/org/kar/archidata/tools/JWTWrapper.java b/src/org/kar/archidata/tools/JWTWrapper.java
index 4ae652a..d38725a 100644
--- a/src/org/kar/archidata/tools/JWTWrapper.java
+++ b/src/org/kar/archidata/tools/JWTWrapper.java
@@ -51,13 +51,13 @@ class TestSigner implements JWSSigner {
@Override
public Set supportedJWSAlgorithms() {
// TODO Auto-generated method stub
- return null;
+ return Set.of(JWSAlgorithm.RS256);
}
@Override
public JCAContext getJCAContext() {
// TODO Auto-generated method stub
- return null;
+ return new JCAContext();
}
}
@@ -209,8 +209,9 @@ public class JWTWrapper {
try {
// On the consumer side, parse the JWS and verify its RSA signature
final SignedJWT signedJWT = SignedJWT.parse(signedToken);
-
- if (rsaPublicJWK == null) {
+ if (ConfigBaseVariable.getTestMode() && signedToken.endsWith(TestSigner.test_signature)) {
+ LOGGER.warn("Someone use a test token: {}", signedToken);
+ } else if (rsaPublicJWK == null) {
LOGGER.warn("JWT public key is not present !!!");
if (!ConfigBaseVariable.getTestMode()) {
return null;
@@ -251,16 +252,16 @@ public class JWTWrapper {
return null;
}
- public static String createJwtTestToken(final long userID, final String userLogin, final String isuer, final String application, final Map rights) {
+ public static String createJwtTestToken(final long userID, final String userLogin, final String isuer, final String application, final Map> rights) {
if (!ConfigBaseVariable.getTestMode()) {
LOGGER.error("Test mode disable !!!!!");
return null;
}
try {
- final int timeOutInMunites = 3600 * 24 * 31;
+ final int timeOutInMunites = 3600;
final Date now = new Date();
- final Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
+ final Date expiration = new Date(new Date().getTime() + timeOutInMunites * 1000 /* ms */);
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
@@ -278,7 +279,8 @@ public class JWTWrapper {
// serialize the output...
return signedJWT.serialize();
} catch (final Exception ex) {
- LOGGER.error("Can not generate Test Token...");
+ ex.printStackTrace();
+ LOGGER.error("Can not generate Test Token... {}", ex.getLocalizedMessage());
}
return null;
}
diff --git a/src/org/kar/archidata/tools/RESTApi.java b/src/org/kar/archidata/tools/RESTApi.java
index e0571e3..a987701 100644
--- a/src/org/kar/archidata/tools/RESTApi.java
+++ b/src/org/kar/archidata/tools/RESTApi.java
@@ -16,6 +16,7 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import jakarta.ws.rs.core.HttpHeaders;
@@ -60,8 +61,12 @@ public class RESTApi {
final HttpResponse httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) {
// LOGGER.error("catch error from REST API: {}", httpResponse.body());
- final RESTErrorResponseExeption out = mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class);
- throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage);
+ try {
+ final RESTErrorResponseExeption out = mapper.readValue(httpResponse.body(), RESTErrorResponseExeption.class);
+ throw new RESTErrorResponseExeption(out.uuid, out.time, out.error, out.message, out.status, out.statusMessage);
+ } catch (final MismatchedInputException ex) {
+ throw new IOException("Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body());
+ }
}
// LOGGER.error("status code: {}", httpResponse.statusCode());
// LOGGER.error("data: {}", httpResponse.body());
@@ -120,9 +125,16 @@ public class RESTApi {
public T put(final Class clazz, final String urlOffset, final U data) throws RESTErrorResponseExeption, IOException, InterruptedException {
final ObjectMapper mapper = new ObjectMapper();
- final HttpClient client = HttpClient.newHttpClient();
final String body = mapper.writeValueAsString(data);
+ return putJson(clazz, urlOffset, body);
+ }
+
+ public T putJson(final Class clazz, final String urlOffset, final String body) throws RESTErrorResponseExeption, IOException, InterruptedException {
+ final ObjectMapper mapper = new ObjectMapper();
+ final HttpClient client = HttpClient.newHttpClient();
Builder requestBuilding = HttpRequest.newBuilder().uri(URI.create(this.baseUrl + urlOffset));
+ LOGGER.trace("call PUT: {}", URI.create(this.baseUrl + urlOffset));
+ LOGGER.trace("DATA: {}", body);
if (this.token != null) {
requestBuilding = requestBuilding.header(HttpHeaders.AUTHORIZATION, "Yota " + this.token);
}
diff --git a/test/src/test/kar/archidata/TestListJson.java b/test/src/test/kar/archidata/TestListJson.java
new file mode 100644
index 0000000..9875698
--- /dev/null
+++ b/test/src/test/kar/archidata/TestListJson.java
@@ -0,0 +1,99 @@
+package test.kar.archidata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.kar.archidata.GlobalConfiguration;
+import org.kar.archidata.dataAccess.DataAccess;
+import org.kar.archidata.dataAccess.DataFactory;
+import org.kar.archidata.db.DBEntry;
+import org.kar.archidata.tools.ConfigBaseVariable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import test.kar.archidata.model.SerializeListAsJson;
+
+@ExtendWith(StepwiseExtension.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class TestListJson {
+ final static private Logger LOGGER = LoggerFactory.getLogger(TestListJson.class);
+
+ @BeforeAll
+ public static void configureWebServer() throws Exception {
+ if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) {
+ ConfigBaseVariable.dbType = "sqlite";
+ ConfigBaseVariable.dbHost = "memory";
+ // for test we need to connect all time the DB
+ ConfigBaseVariable.dbKeepConnected = "true";
+ }
+ // Connect the dataBase...
+ final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig);
+ entry.connect();
+ }
+
+ @AfterAll
+ public static void removeDataBase() throws IOException {
+ LOGGER.info("Remove the test db");
+ DBEntry.closeAllForceMode();
+ ConfigBaseVariable.clearAllValue();
+ }
+
+ @Order(1)
+ @Test
+ public void testTableInsertAndRetrieve() throws Exception {
+ final List sqlCommand = DataFactory.createTable(SerializeListAsJson.class);
+ for (final String elem : sqlCommand) {
+ LOGGER.debug("request: '{}'", elem);
+ DataAccess.executeSimpleQuerry(elem, false);
+ }
+ }
+
+ @Order(2)
+ @Test
+ public void testIO() throws Exception {
+ final SerializeListAsJson test = new SerializeListAsJson();
+ test.data = new ArrayList<>();
+ test.data.add(5);
+ test.data.add(2);
+ test.data.add(8);
+ test.data.add(6);
+ test.data.add(51);
+
+ final SerializeListAsJson insertedData = DataAccess.insert(test);
+
+ Assertions.assertNotNull(insertedData);
+ Assertions.assertNotNull(insertedData.id);
+ Assertions.assertTrue(insertedData.id >= 0);
+ Assertions.assertNotNull(insertedData.data);
+ Assertions.assertEquals(5, insertedData.data.size());
+ Assertions.assertEquals(test.data.get(0), insertedData.data.get(0));
+ Assertions.assertEquals(test.data.get(1), insertedData.data.get(1));
+ Assertions.assertEquals(test.data.get(2), insertedData.data.get(2));
+ Assertions.assertEquals(test.data.get(3), insertedData.data.get(3));
+ Assertions.assertEquals(test.data.get(4), insertedData.data.get(4));
+
+ // Try to retrieve all the data:
+ final SerializeListAsJson retrieve = DataAccess.get(SerializeListAsJson.class, insertedData.id);
+
+ Assertions.assertNotNull(retrieve);
+ Assertions.assertNotNull(retrieve.id);
+ Assertions.assertTrue(retrieve.id >= 0);
+ Assertions.assertNotNull(retrieve.data);
+ Assertions.assertEquals(5, retrieve.data.size());
+ Assertions.assertEquals(test.data.get(0), retrieve.data.get(0));
+ Assertions.assertEquals(test.data.get(1), retrieve.data.get(1));
+ Assertions.assertEquals(test.data.get(2), retrieve.data.get(2));
+ Assertions.assertEquals(test.data.get(3), retrieve.data.get(3));
+ Assertions.assertEquals(test.data.get(4), retrieve.data.get(4));
+ }
+
+}
diff --git a/test/src/test/kar/archidata/TestTypes.java b/test/src/test/kar/archidata/TestTypes.java
index 89a0903..0c87596 100644
--- a/test/src/test/kar/archidata/TestTypes.java
+++ b/test/src/test/kar/archidata/TestTypes.java
@@ -449,7 +449,7 @@ public class TestTypes {
"varcharData": null
}
""";
- final int nbUpdate = DataAccess.updateWithJson(TypesTable.class, insertedData.id, jsonData);
+ final int nbUpdate = DataAccess.updateWithJson(TypesTable.class, insertedData.id, jsonData, null);
Assertions.assertEquals(1, nbUpdate);
// Get new data
diff --git a/test/src/test/kar/archidata/model/SerializeListAsJson.java b/test/src/test/kar/archidata/model/SerializeListAsJson.java
new file mode 100644
index 0000000..7fbda65
--- /dev/null
+++ b/test/src/test/kar/archidata/model/SerializeListAsJson.java
@@ -0,0 +1,13 @@
+package test.kar.archidata.model;
+
+import java.util.List;
+
+import org.kar.archidata.annotation.DataJson;
+import org.kar.archidata.model.GenericData;
+
+public class SerializeListAsJson extends GenericData {
+
+ @DataJson
+ public List data;
+
+}
\ No newline at end of file