Souci de lecture d'un fichier issu d'une confirmation d'action

Bonjour,

Nous rencontrons des difficultés pour importer et lire un fichier via l’action TDF_import_Referent_Site. Voici les détails de l’action et les logs associés :
ACTION : TDF_import_Referent_Site
ACTION Attribut : TDF_File_import_Referent_Site
Fonction : TDF_SIT_TDF_IMPORT_REFERENT_SITE_A

Code de l’action

@BusinessObjectAction
public void importsiteREF(Action action) {
    ObjectField docField = action.getConfirmField("TDF_File_import_Referent_Site");
    AppLog.info(getClass(), "importsiteREF", "Valeur du champ TDF_File_import_Referent_Site: " + docField, getGrant());

    if (docField != null) {
        DocumentDB doc = docField.getDocument();
        if (doc == null) {
            AppLog.error(getClass(), "importsiteREF", "Le DocumentDB est null après récupération", null, getGrant());
        }

        if (doc != null) {
            File file = doc.getUploadFile();
            if (file != null) {
                String fileName = file.getName();
                AppLog.info(getClass(), "importsiteREF", "Nom du fichier: " + fileName, getGrant());

                try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        AppLog.info(getClass(), "importsiteREF", "Contenu : " + line, getGrant());
                    }
                } catch (IOException e) {
                    AppLog.error(getClass(), "importsiteREF", "Erreur lors de la lecture du fichier : " + fileName, null, getGrant());
                }

                if (file.delete()) {
                    AppLog.info(getClass(), "importsiteREF", "Fichier temporaire supprimé : " + fileName, getGrant());
                } else {
                    AppLog.error(getClass(), "importsiteREF", "Erreur lors de la suppression du fichier temporaire : " + fileName, null, getGrant());
                }
            } else {
                AppLog.error(getClass(), "importsiteREF", "Le fichier est null", null, getGrant());
            }
        } else {
            AppLog.error(getClass(), "importsiteREF", "Le DocumentDB est null", null, getGrant());
        }
    } else {
        AppLog.error(getClass(), "importsiteREF", "Le champ de document est null", null, getGrant());
    }
}

Logs
Voici les logs associés à l’exécution de l’action :

2024-10-09 16:15:00,463|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM005|system|com.simplicite.util.CronJob|run||Résultat de la tâche TdfSite-TDF_import_Referent_Site :
2024-10-09 16:15:00,463|SIMPLICITE|ERROR||http://tdf.simplicite.io:10028||ERROR|safae.safari@prestataires.tdf.fr|com.simplicite.objects.TdfInfra.TdfSite|importsiteREF||Evénement: Le DocumentDB est null
2024-10-09 16:15:00,463|SIMPLICITE|ERROR||http://tdf.simplicite.io:10028||ERROR|safae.safari@prestataires.tdf.fr|com.simplicite.objects.TdfInfra.TdfSite|importsiteREF||Evénement: Le DocumentDB est null après récupération
2024-10-09 16:15:00,463|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||INFO|safae.safari@prestataires.tdf.fr|com.simplicite.objects.TdfInfra.TdfSite|importsiteREF||Evénement: Valeur du champ TDF_File_import_Referent_Site: {"filter":"%","input":"TDF_File_import_Referent_Site","default":"","name":"TDF_File_import_Referent_Site","id":"9258","label":"TDF file import referent site","type":17,"value":"0","fullinput":"TDF_File_import_Referent_Site","oldvalue":""}
2024-10-09 16:15:00,463|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM004|system|com.simplicite.util.CronJob|run||Execute la tâche TdfSite-TDF_import_Referent_Site à la date 2024-10-09 16:15:00

Bonjour

Pour bien comprendre : vous avez configuré un attribut d’action de type fichier ?
Et vous essayez de le lire dans la méthode d’action en l’executant dans la UI standard, c’est ça ?

Pouvez vous mettre des copies d’écran pour illustrer ce que vous faites exactement ?

De quel(s) type(s) est ce fichier (texte ou binaire) ?

Quelle est la version exacte (x.y.z) de Simplicité que vous utilisez actuellement ?

Bonjour,

La version de Simplicité que nous utilisons est : 5.3.51 .

Voici les détails de l’action :

Détails de l’attribut :

Résumé de la configuration de l’attribut TDF_File_import_Referent_Site pour l’objet métier TdfSite :

Détails de l’Attribut

Nom logique : TDF_File_import_Referent_Site

Nom physique : TDF_File_import_Referent_Site

Nom du Module : TdfInfra

Valeur par défaut : [Non spécifiée]

Description : [Non spécifiée]

Classification : [Non spécifiée]

Type

Type : Document

Longueur : 11

Précision : [Non spécifiée]

Taille minimale : [Non spécifiée]

Type de validation : [Non spécifié]

Options

Clé fonctionnelle : Oui

Modifiable : Partout

Indexable : Oui

Auto-complétion : Non

Autoriser le group by : Oui

Syntaxe d’auto-incrémentation : [Non spécifiée]

Obligatoire : Oui

Recopiable : Oui

Mise à jour en masse : Oui

Exportable : Oui

Affichage : Visible

Recherche possible : Oui

Recherche obligatoire : Non

Type de tri : [Non spécifié]

Tri par code : [Non spécifié]

Présentation : [Non spécifiée]

Étendu ? Non

Étendu en liste ? Non

Procédure : ce que nous faisons exactement :

  1. On clique sur le bouton d’action « Importer référent site ».

  2. On choisit un fichier CSV.

Un message apparaît en pop-up indiquant que l’action a été lancée avec succès.

Dans les logs, nous avons le message que le DocumentDB est nul.

Bonjour,

Merci pour votre retour détaillé,

Il faut passer l’action en synchrone pour ne pas la lancer comme une tache cron isolée qui ne récupère plus les paramètres de la session utilisateur. Avec ce paramétrage c’est comme si la méthode était appelée la nuit / sans paramètre.

Si le traitement du fichier est long, il faudra lancer le job asynchrone depuis la méthode de l’action synchrone / une fois le fichier récupéré, par exemple :

@BusinessObjectAction
public String importsiteREF(Action action) {
	// synchronous call form UI with confirm fields in user session
	ObjectField docField = action.getConfirmField("TDF_File_import_Referent_Site");
	DocumentDB doc = docField!=null ? docField.getDocument() : null;
	final File file = doc!=null ? doc.getUploadFile() : null;
	if (file!=null) {
		// Launch async task
		JobQueue.push("ImportSiteREFJob", new Runnable() {
			@Override
			public void run() {
				doImportSite(file);
			}
		}, Thread.NORM_PRIORITY);
	}
	...
}

private void doImportSite(File file) {
	// ... todo ...
	// clean when used
	file.delete();
}

Bonjour,

Merci pour votre retour concernant mon précédent message. J’ai essayé de modifier le code comme suggéré, mais j’ai rencontré un souci avec JobQueue. Voici une capture d’écran des erreurs que j’ai obtenues lors de la compilation :


@BusinessObjectAction
public String importsiteREF(Action action) {
    ObjectField docField = action.getConfirmField("TDF_File_import_Referent_Site");
    DocumentDB doc = docField != null ? docField.getDocument() : null;
    final File file = doc != null ? doc.getUploadFile() : null;

    if (file != null) {
        JobQueue.push("ImportSiteREFJob", new Runnable() {
            @Override
            public void run() {
                try {
                    doImportSite(file);
                } catch (Exception e) {
                    AppLog.error("Erreur lors de l'importation : " + e.getMessage(), e, getGrant());
                }
            }
        }, Thread.NORM_PRIORITY);
    }
    
    return "Processus d'importation initié.";
}

private void doImportSite(File file) {
    try {
        // Lire le contenu du fichier
        String content = new String(Files.readAllBytes(file.toPath()));
        
        // Journaliser le contenu du fichier
        AppLog.info("Contenu du fichier : " + content,getGrant());

        // Logique d'importation ici
    } catch (IOException e) {
        AppLog.error("Erreur lors de la lecture du fichier : " + e.getMessage(), e, getGrant());
    } finally {
        // Nettoyer le fichier
        if (file.exists() && !file.delete()) {
             AppLog.error("Échec de la suppression du fichier : " + file.getAbsolutePath(), null, getGrant());

        } 
    }
}

Merci d’avance pour votre assistance.

Effectivement en V5, JobQueue était dans un autre package interne et n’avait pas encore la priorité du Thread en paramètre, il a été déplacé dans le package com.simplicite.util en V6 pour être visible dans la Javadoc V6 :

https://platform.simplicite.io/6.1/javadoc/com/simplicite/util/JobQueue.html#push(java.lang.String,java.lang.Runnable)

En attendant de passer en V6, utilisez l’ancienne syntaxe suivante en V5 :

com.simplicite.util.engine.JobQueue("jobName", runnable);

Elle restera compatible en V6, mais vous pourrez changer en :

com.simplicite.util.JobQueue("jobName", runnable, priority);

Bonjour,
Je vous écris pour partager les résultats de la dernière tentative d’importation du fichier dans la tâche TdfSite-TDF_import_Referent_Site. Voici les logs pertinents :

2024-10-14 12:09:11,079|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM005|system|com.simplicite.util.CronJob|run||Résultat de la tâche TdfSite-TDF_import_Referent_Site : Processus d'importation initié.

2024-10-14 12:09:11,079|SIMPLICITE|ERROR||http://tdf.simplicite.io:10028||ERROR|safae.safari@prestataires.tdf.fr|com.simplicite.objects.TdfInfra.TdfSite|importsiteREF||Evénement: **Le fichier est nul, vérifiez le champ de document.**

2024-10-14 12:09:11,078|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM004|system|com.simplicite.util.CronJob|run||Execute la tâche TdfSite-TDF_import_Referent_Site à la date 2024-10-14 12:09:11

2024-10-14 12:05:00,026|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM005|system|com.simplicite.util.CronJob|run||Résultat de la tâche PruneSessions : 0 row deleted.#INFO

2024-10-14 12:05:00,026|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM005|system|com.simplicite.util.CronJob|run||Résultat de la tâche ObjectDynGC : ObjectDynGC cleared 0 object(s) dynamic data.#INFO

2024-10-14 12:05:00,025|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||ICORECM004|system|com.simplicite.util.CronJob|run||Execute la tâche PruneSessions à la date 2024-10-14 12:05:00

2024-10-14 12:05:00,021|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||MEMGC|system|com.simplicite.util.tools.SystemTool|objectGC||Dyn=0 Full=0

2024-10-14 12:05:00,017|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||INFO|system|com.simplicite.util.engine.CronManager|run||Evénement: Cron manager is sleeping for 0:04:59...

2024-10-14 12:05:00,017|SIMPLICITE|INFO||http://tdf.simplicite.io:10028||INFO|system|com.simplicite.util.engine.CronManager|run||Evénement: Next cron job: deadlockTimestamp at Mon Oct 14 12:10:00 CEST 2024

Comme on peut le voir dans les logs, une erreur est survenue indiquant que “Le fichier est nul, vérifiez le champ de document”. Cela signifie que le fichier que nous tentions d’importer n’a pas été trouvé ou n’a pas été correctement transmis au processus.

Code:
Nous avons également ajouté des journaux pour faciliter le diagnostic et améliorer le suivi des erreurs :

@BusinessObjectAction
public String importsiteREF(Action action) {
    ObjectField docField = action.getConfirmField("TDF_File_import_Referent_Site");
    DocumentDB doc = docField != null ? docField.getDocument() : null;
    final File file = doc != null ? doc.getUploadFile() : null;
    if (file != null) {
    	 AppLog.info(getClass(),"importsiteREF","Fichier à importer : " + file.getAbsolutePath(), getGrant());
        // Utiliser la syntaxe de V5
        com.simplicite.util.engine.JobQueue.push("ImportSiteREFJob", new Runnable() {
            @Override
            public void run() {
                try {
                    doImportSite(file);
                } catch (Exception e) {
                    AppLog.error("Erreur lors de l'importation : " + e.getMessage(), e, getGrant());
                }
            }
        });
    }else{
    	
    	AppLog.error(getClass(), "importsiteREF","Le fichier est nul, vérifiez le champ de document.", (Throwable) null	, getGrant());
    }
    
    return "Processus d'importation initié.";
}

private void doImportSite(File file) {
   if (!file.exists()) {
        AppLog.error(getClass(), "importsiteREF","Le fichier n'existe pas : " + file.getAbsolutePath(),  (Throwable) null	, getGrant());
        return;
    }
   
    try {
        // Lire le contenu du fichier
        String content = new String(Files.readAllBytes(file.toPath()));
        
        // Journaliser le contenu du fichier
        AppLog.info("Contenu du fichier : " + content, getGrant());

        // Logique d'importation ici
    } catch (IOException e) {
        AppLog.error("Erreur lors de la lecture du fichier : " + e.getMessage(), e, getGrant());
    } finally {
        // Nettoyer le fichier
        if (file.exists() && !file.delete()) {
             AppLog.error("Échec de la suppression du fichier : " + file.getAbsolutePath(), null, getGrant());

        } 
    }
}

Merci de vos retours et suggestions pour résoudre cette situation.

Bonjour,

Comme indiqué plus haut, avez vous passé votre Action en synchrone ? Si elle est lancée de façon isolée aucun paramètre ne lui sera passé.

image

Sinon merci de nous donner son paramétrage exact pour reproduire votre cas de fichier nul.

Bonjour,
Concernant votre question, l’action TDF_import_Referent_Site est bien configurée pour une exécution en mode synchrone.

Voici les détails exacts de sa configuration actuelle :

Pour paramétrage de l’attribut : TDF_File_import_Referent_Site:

Bonjour,

Avez-vous pu reproduire le cas avec les éléments que j’ai fournis ?
Je reste disponible si vous avez besoin de plus d’informations.

Merci d’avance pour votre retour.

Merci pour ces informations, rien d’anormal qui me saute aux yeux, on va refaire un test en 5.3 avec ce paramétrage.

L’action de liste synchrone fonctionne bien en 5.3 avec ce paramétrage.
J’ai testé en ajoutant une action à l’objet DemoSupplier de la Demo, et en utilisant votre attribut TDF_File_import_Referent_Site, avec le même code :

public class DemoSupplier extends ObjectDB {
	private static final long serialVersionUID = 1L;
	
	public String demoImportFile(Action action) {
	    ObjectField docField = action.getConfirmField("TDF_File_import_Referent_Site");
	    DocumentDB doc = docField != null ? docField.getDocument() : null;
	    final File file = doc != null ? doc.getUploadFile() : null;
	 // ...

A l’exécution, on obtient bien un fichier temporaire docparam-xxx

INFO|designer|com.simplicite.objects.Demo.DemoSupplier|importsiteREF|Event: Fichier à importer : .../WEB-INF/tmp/docparam-1728994626135-sGQVg2tHo2QEBDVQuaREjSIbvD0WTKFn.xml

J’ai noté 2 choses dans votre paramétrage :

  • TDF_File_import_Referent_Site : le champ n’est pas sensé avoir de colonne physique, car il n’y a pas de persistance pour un attribut d’action. Il faut que votre attribut soit dédié à l’action (et ne serve pas dans d’autres objets). Si vous utilisez un attribut de votre objet dans l’action, il sera présenté en lecture seule (pour confirmation de la valeur saisie dans le formulaire).
  • Le retour de la méthode “Processus d’importation initié.” est considéré par Simplicité comme une erreur par défaut, pour retourner une info/warning… il faut utiliser les helpers comme :
    return Message.formatSimpleInfo("Processus d'importation initié.");
    sinon le popup de confirmation reste affiché.

Sinon

  • Le fichier importé est-il gros ? Avez vous testé avec un petit fichier ? Il est peut être filtré par une limitation réseau ou tomcat ou paramètre MAX_UPLOAD_SIZE ?
  • Avez vous essayé de l’uploader dans un champ de type Document depuis un objet quelconque ?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.