From bb1239f316a256594e1347beb3e792c28224a96a Mon Sep 17 00:00:00 2001
From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr>
Date: Fri, 31 May 2024 13:42:06 +0200
Subject: [PATCH] Correction bug #230

---
 .../configuration/ConfigurationException.java | 14 +++-
 .../configuration/JacksonErrorParser.java     | 70 +++++++++++++++++++
 .../builder/ConfigurationBuilder.java         |  8 +++
 ui/src/locales/en.json                        | 34 ++++++++-
 ui/src/locales/fr.json                        | 36 +++++++++-
 5 files changed, 158 insertions(+), 4 deletions(-)
 create mode 100644 src/main/java/fr/inra/oresing/rest/model/configuration/JacksonErrorParser.java

diff --git a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java
index c5f6b4ef3..3358f0b1b 100644
--- a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java
+++ b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java
@@ -221,8 +221,20 @@ public enum ConfigurationException {
     DUPLICATED_COMPONENT_HEADER,
     INVALID_CONFIGURATION_FILE,
     ADDING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR,
-    REMOVING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR;
+    REMOVING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR,
 
+    /*
+    jackson parse exeption
+     */
+
+    DUPLICATE_KEY,
+    UNEXPECTED_CHARACTER,
+    INVALID_TOKEN,
+    UNEXPECTED_EOF,
+    MALFORMED_NUMBER,
+    UNTERMINATED_STRING,
+    MALFORMED_COMMENT,
+    UNKNOWN;
 
     private final String message;
 
diff --git a/src/main/java/fr/inra/oresing/rest/model/configuration/JacksonErrorParser.java b/src/main/java/fr/inra/oresing/rest/model/configuration/JacksonErrorParser.java
new file mode 100644
index 000000000..4fd3735d7
--- /dev/null
+++ b/src/main/java/fr/inra/oresing/rest/model/configuration/JacksonErrorParser.java
@@ -0,0 +1,70 @@
+package fr.inra.oresing.rest.model.configuration;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonLocation;
+import fr.inra.oresing.domain.exceptions.configuration.ConfigurationException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JacksonErrorParser {
+
+    public static ValidationError parse(JsonParseException e) {
+        ConfigurationException errorType = determineErrorType(e);
+        Map<String, Object> errorDetails = extractErrorDetails(e);
+
+        return new ValidationError(errorType, errorDetails);
+    }
+
+    private static ConfigurationException determineErrorType(JsonParseException e) {
+        // Logique pour déterminer le type d'erreur en fonction du message de l'exception
+        String errorMessage = e.getOriginalMessage().toLowerCase();
+
+        if (errorMessage.contains("duplicate field")) {
+            return ConfigurationException.DUPLICATE_KEY;
+        } else if (errorMessage.contains("unexpected character")) {
+            return ConfigurationException.UNEXPECTED_CHARACTER;
+        } else if (errorMessage.contains("invalid token")) {
+            return ConfigurationException.INVALID_TOKEN;
+        } else if (errorMessage.contains("unexpected end-of-input")) {
+            return ConfigurationException.UNEXPECTED_EOF;
+        } else if (errorMessage.contains("malformed number")) {
+            return ConfigurationException.MALFORMED_NUMBER;
+        } else if (errorMessage.contains("unclosed string")) {
+            return ConfigurationException.UNTERMINATED_STRING;
+        } else if (errorMessage.contains("malformed comment")) {
+            return ConfigurationException.MALFORMED_COMMENT;
+        } else {
+            return ConfigurationException.UNKNOWN;
+        }
+    }
+
+    private static Map<String, Object> extractErrorDetails(JsonParseException e) {
+        Map<String, Object> details = new HashMap<>();
+        JsonLocation location = e.getLocation();
+
+        if (location != null) {
+            details.put("lineNumber", location.getLineNr());
+            details.put("columnNumber", location.getColumnNr());
+        }
+
+        // Ajoutez des informations supplémentaires selon le type d'erreur
+        String errorMessage = e.getOriginalMessage().toLowerCase();
+
+        if (errorMessage.contains("duplicate field")) {
+            // Logique pour extraire les clés dupliquées si possible
+            details.put("duplicateKeys", extractDuplicateKeys(errorMessage));
+        }
+
+        return details;
+    }
+
+    private static String extractDuplicateKeys(String errorMessage) {
+        // Logique pour extraire les clés dupliquées du message d'erreur
+        // Exemple de message : "duplicate field 'vcat_label_fr'"
+        String key = errorMessage.substring(errorMessage.indexOf("'") + 1, errorMessage.lastIndexOf("'"));
+        return key;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/ConfigurationBuilder.java b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/ConfigurationBuilder.java
index 475a35ba5..687066d56 100644
--- a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/ConfigurationBuilder.java
+++ b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/ConfigurationBuilder.java
@@ -1,5 +1,6 @@
 package fr.inra.oresing.rest.model.configuration.builder;
 
+import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
@@ -7,10 +8,13 @@ import com.jayway.jsonpath.DocumentContext;
 import com.jayway.jsonpath.JsonPath;
 import fr.inra.oresing.domain.application.configuration.Configuration;
 import fr.inra.oresing.domain.exceptions.configuration.ConfigurationException;
+import fr.inra.oresing.rest.model.configuration.JacksonErrorParser;
 import fr.inra.oresing.rest.model.configuration.ValidationError;
 import fr.inra.oresing.rest.reactive.ReactiveProgression;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
 public record ConfigurationBuilder(RootBuilder rootBuilder) {
 
@@ -24,6 +28,10 @@ public record ConfigurationBuilder(RootBuilder rootBuilder) {
         try {
             rootNode = mapper.readTree(bytes);
             documentContext = JsonPath.parse(mapper.writeValueAsString(rootNode));
+        } catch (JsonParseException jpe) {
+            progression.pushError(JacksonErrorParser.parse(jpe));
+            progression.complete();
+            return null;
         } catch (final IOException e) {
             progression.pushError(new ValidationError(ConfigurationException.INVALID_CONFIGURATION_FILE.getMessage()));
             progression.complete();
diff --git a/ui/src/locales/en.json b/ui/src/locales/en.json
index 9e6370a9f..18a2a2930 100644
--- a/ui/src/locales/en.json
+++ b/ui/src/locales/en.json
@@ -486,6 +486,38 @@
     }
   },
   "errors-yaml": {
+    "duplicateKey": {
+      "title": "Configuration File Error",
+      "message": "One or more duplicate keys were detected in your configuration file at line {lineNumber}. The keys in question are: {duplicateKeys}. Please check and correct the duplicate keys."
+    },
+    "unexpectedCharacter": {
+      "title": "Configuration File Error",
+      "message": "An unexpected character was found in your configuration file at line {lineNumber}, column {columnNumber}. Please check and correct this character."
+    },
+    "invalidToken": {
+      "title": "Configuration File Error",
+      "message": "An invalid token was detected in your configuration file at line {lineNumber}, column {columnNumber}. This indicates an error in the syntax of your configuration file. Please check and correct this error."
+    },
+    "unexpectedEof": {
+      "title": "Configuration File Error",
+      "message": "The end of the file was reached unexpectedly in your configuration file at line {lineNumber}, column {columnNumber}. It seems that your configuration file is incomplete. Please check and complete the file."
+    },
+    "malformedNumber": {
+      "title": "Configuration File Error",
+      "message": "A malformed number was found in your configuration file at line {lineNumber}, column {columnNumber}. Please check the syntax of the numbers in your configuration file and correct this error."
+    },
+    "unterminatedString": {
+      "title": "Configuration File Error",
+      "message": "An unterminated string was detected in your configuration file at line {lineNumber}, column {columnNumber}. Please ensure that all strings are properly closed with quotation marks."
+    },
+    "malformedComment": {
+      "title": "Configuration File Error",
+      "message": "A malformed comment was found in your configuration file at line {lineNumber}, column {columnNumber}. Please check the syntax of the comments in your configuration file and correct this error."
+    },
+    "unknown": {
+      "title": "Configuration File Error",
+      "message": "An unknown error occurred in your configuration file at line {lineNumber}, column {columnNumber}. Please check the integrity of your configuration file."
+    },
     "badBooleanRequiredSections": {
       "message": "Only the values <code><B> true </B></code> or <code><B> false </B></code> are allowed.",
       "title": ""
@@ -752,7 +784,7 @@
     "user-role": "Role: "
   },
   "message": {
-    "app-config-error": "Error in yaml file",
+    "app-config-error": "Error in configuration file",
     "close": "Close message",
     "csv-config-error": "Error in csv file",
     "data-type-config-error": "Error in csv file",
diff --git a/ui/src/locales/fr.json b/ui/src/locales/fr.json
index c8a5610f1..d6cf6aede 100644
--- a/ui/src/locales/fr.json
+++ b/ui/src/locales/fr.json
@@ -484,7 +484,39 @@
       "message": "Le nombre de jetons(token) est inattendu. Nombre attendu : <code>{expectedTokenCount}</code><br/>L'en-tête actuel : <code>{actualHeader}</code> comprend <code>{actualTokenCount}</code> tokens"
     }
   },
-  "errors-yaml": {
+  "errors-yaml": {"duplicateKey": {
+    "title": "Erreur dans le fichier de configuration",
+    "message": "Une ou plusieurs clés dupliquées ont été détectées dans votre fichier de configuration à la ligne {lineNumber}. Les clés en question sont : {duplicateKeys}. Veuillez vérifier et corriger les clés dupliquées."
+  },
+    "unexpectedCharacter": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "Un caractère inattendu a été trouvé dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Veuillez vérifier et corriger ce caractère."
+    },
+    "invalidToken": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "Un jeton invalide a été détecté dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Cela indique une erreur dans la syntaxe de votre fichier de configuration. Veuillez vérifier et corriger cette erreur."
+    },
+    "unexpectedEof": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "La fin du fichier a été atteinte de manière inattendue dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Il semble que votre fichier de configuration soit incomplet. Veuillez vérifier et compléter le fichier."
+    },
+    "malformedNumber": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "Un nombre mal formé a été trouvé dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Veuillez vérifier la syntaxe des nombres dans votre fichier de configuration et corriger cette erreur."
+    },
+    "unterminatedString": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "Une chaîne de caractères non terminée a été détectée dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Veuillez vous assurer que toutes les chaînes de caractères sont correctement fermées par des guillemets."
+    },
+    "malformedComment": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "Un commentaire mal formé a été trouvé dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Veuillez vérifier la syntaxe des commentaires dans votre fichier de configuration et corriger cette erreur."
+    },
+    "unknown": {
+      "title": "Erreur dans le fichier de configuration",
+      "message": "Une erreur inconnue est survenue dans votre fichier de configuration à la ligne {lineNumber}, colonne {columnNumber}. Veuillez vérifier l'intégrité de votre fichier de configuration."
+    },
+
     "path": "Pour le chemin : ",
     "badBooleanRequiredSections": {
       "message": "Seules les valeurs 'true' ou 'false' sont admises.",
@@ -764,7 +796,7 @@
     "user-role": "Rôle: "
   },
   "message": {
-    "app-config-error": "Erreur dans le fichier yaml",
+    "app-config-error": "Erreur dans le fichier de configuration",
     "close": "Fermer le message",
     "csv-config-error": "Erreur dans le fichier csv",
     "data-type-config-error": "Erreur dans le fichier csv",
-- 
GitLab