"Method not found in object" pour certain users

Tags: #<Tag:0x00007f80fdd6f9b8>

Bonjour,

Avec certains users, le mien entre autre, des boutonts d’action ne fonctionnent pas ou alors une fois sur 10 apres clear cache, relog. Lorsque ça ne fonctionne pas j’ai cette erreur là:

020-11-03 10:38:53,466 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|http://ip-172-22-2-34.eu-west-3.compute.internal:8080||ERROR|jm|com.simplicite.util.engine.ObjectManager|invokeAction||Evénement: Method openDemandeTransfertForm not found in object NamJeune

Par contre il fonctionne bien avec le user designer. Est-ce que ça peut venir des groupes de responsabilité ? J’ai vérifié avec mon user et il appartiens bien aux bon groupes. Est ce que c’est un comportement qui a déjà été reproduit de votre coté? Ou puis-je recherche les causes de ce problème ?

Merci d’avance

Une méthode “not found” n’est pas liée aux droits, mais à la compilation de votre objet.

Il doit y avoir des erreurs Java sur cet objet ou un autre, qui ne permettent pas de déployer le JAR de votre module sur la plateforme. Si un objet ne compile pas, rien ne peut être poussé dans le classloader.

Mais si la méthode est bien là dans son .class, elle le sera pour toutes les instances (de différentes sessions) de cette classe. Vous pouvez regarder dans WEB-INF/build et /bin si le JAR et la class sont présents à la date de dernière compilation sans erreur.

Bonjour,

J’ai une question suite a votre réponse :
comment on peut avoir un objet qui ne compile pas ?
Il me semblait que le code java passait par l’éditeur intégré et que la sauvegarde lançais une compilation de la dites classe ?

Nous avons cette trace dans les logs qui apparait plusieurs fois au moment du clear cache :

2020-11-03 14:08:41,132 ERROR [com.simplicite.util.engine.CoreCache] SIMPLICITE|http://*****:8080||ECOREGT002|system|com.simplicite.util.engine.CoreCache|instantiateObject||Corriger la classe ou l'objet ObjectIndex
    java.lang.NullPointerException
2020-11-03 14:08:41,132 FATAL [com.simplicite.util.ObjectDirect] SIMPLICITE|http://*****:8080||FCOREOM002|system|com.simplicite.util.ObjectDirect|init||Erreur d'initialisation de l'objet ObjectIndex pour l'utilisateur system
    java.lang.NullPointerException
     at com.simplicite.util.engine.CoreCache.getTimesheets(CoreCache.java:3234)
     at com.simplicite.util.engine.ObjectLoader.loadTimesheet(ObjectLoader.java:2274)
     at com.simplicite.util.engine.ObjectLoader.loadFromDB(ObjectLoader.java:935)
     at com.simplicite.util.engine.ObjectLoader.getClone(ObjectLoader.java:131)
     at com.simplicite.util.engine.ObjectLoader.load(ObjectLoader.java:87)
     at com.simplicite.util.ObjectDirect.init(ObjectDirect.java:41)
     at com.simplicite.util.ObjectDB.init(ObjectDB.java:240)
     at com.simplicite.util.ObjectDB.load(ObjectDB.java:218)
     at com.simplicite.util.engine.CoreCache.instantiateObject(CoreCache.java:3722)
     at com.simplicite.util.engine.CoreCache.getObject(CoreCache.java:3664)
     at com.simplicite.util.engine.GrantManager.getObject(GrantManager.java:95)
     at com.simplicite.util.GrantDirect.getObject(GrantDirect.java:571)
     at com.simplicite.util.Grant.getObject(Grant.java:2026)
     at com.simplicite.util.Grant.getTmpObject(Grant.java:2138)
     at com.simplicite.util.tools.IndexSQLTool.indexFields(IndexSQLTool.java:218)
     at com.simplicite.util.tools.IndexSQLTool.indexation(IndexSQLTool.java:279)
     at com.simplicite.util.engine.ObjectManager.indexObjectSync(ObjectManager.java:4991)
     at com.simplicite.util.engine.ObjectManager$2.run(ObjectManager.java:5028)
     at java.base/java.lang.Thread.run(Thread.java:832)

Mais je ne comprends pas leurs sens

Si vous faites une erreur de syntaxe par exemple
Essayez de compiler int a = "2";

Le “save” fait bien la compilation et le rechargement du JAR.
ou affiche les erreurs de compilation.

La compilation est globale, donc si une de vos classes ne compile pas (pas forcement celle affichée), le JAR n’est pas reconstruit, et l’erreur remontée indique de quelle classe il s’agit.

ok merci pour l’information, je comprend mieux maintenant :)

Il doit y avoir un problème de dépendance dans les chargements. Il essaye d’indexer quelque chose avant que le cache ne soit construit.

On va corriger ce point qui est peut être à l’origine de votre problème (le cache se vide mal).

Voilà, il faut vous mettre à jour et regarder si le problème lors du clear-cache se produit encore.
Les erreurs de compilation ou de loading d’objet sont toujours explicites dans les logs. Donc il faut déjà éteindre toutes les stacks d’erreur, surtout FATAL.

Ensuite, pensez aussi à regarder lors du “save” de votre code si vos classes sont présentes dans WEB-INF/src, puis compilée dans WEB-INF/bin et le JAR zippé dans WEB-INF/build.

C’est normalement inutile mais dans votre cas, il faudra pouvoir identifier à quelle étape il y a un pb.

On en encore eu le cas à l’instant. Toutes les méthodes liées à des actions de fonctionnaient pas. Au redémarrage du container, tout fonctionne sans que le code n’ait changé entre temps. Le clear cache global ne résoud pas le problème.

Voilà un exemple d’action qui ne fonctionne pas :

  public String openChgtEtatCivilAvenantForm() {
        return javascript(
                "var b = app.getBusinessObject('NamContratAvenant', '" + NamInstanceName.AVENANT_CHG_ETAT_CIVIL + "'); " +
                        "$ui.displayForm(null, b, app.DEFAULT_ROW_ID, {nav: 'add', parent: { name: obj.getName(), inst: obj.getInstanceName(), field: 'namCavenantJenId', rowId: obj.getRowId(), object: obj } })"
        );
    }

Vous ne nous donnez aucun des éléments demandés pour vous aider à comprendre pourquoi votre code ne compile pas lors d’un clear-cache. Ce ne sont pas juste vos actions qui ne marcheront pas, ce sont tous vos hooks si le JAR ne peut pas être généré.

  • Votre version à jour ?
  • Les logs (catalina + simplicité) lors du “save” de votre code unitairement et au moment du clear-cache global ? si votre version est à jour il ne devrait plus y avoir le pb sur le getTimesheets null
  • Contenu des répertoires WEB-INF src/bin/build ? vos classes sont-elles présentes à chaque étape de compilation ? pb de disque full… ?

Merci pour vos réponses.

On en a discuté en call tout à l’heure : à priori tout marche bien puis suite à une recompilation (pas forcément lié au code de l’action) le invokeAction ne trouve plus la méthode d’action qu’elle trouvait juste avant…

Pour le moment je n’arrive pas à reproduire le pb. J’ai demandé à avoir le code de l’action pour être dans des conditions les plus proches possibles.

Par contre j’ai oublié de demander si on était bien sur une version à jour avec la correction sur le getTimesheets.

NB1: J’ai commité une remontée de stacktrace dans l’objet manager pour pouvoir avoir plus d’info (notamment la pile d’appel) si ça se reproduit

NB2: on est dans un container Docker donc, à priori, pas de subtilités liées à des pbs d’écriture dans les répertoires de travail src/bin/build (sauf s’il y a une config particulière au niveau des volumes associés au container mais je ne pense pas)

L’erreur sur getTimesheets faisait sortir du clear-cache en erreur, du coup il devait être partiellement terminé.

Il faut regarder explicitement src/bin/jar pour vérifier la présence de la classe + méthode quand le problème se produit.

Si la méthode est bien présente et compilée dans le JAR, c’est alors un problème de runtime/classloader/cast : si Simplicité ne peut pas instancier la classe, il instancie alors un ObjectDB non bloquant de base avec une trace dans les logs pour le designer en lui indiquant explicitement de corriger la classe.

Une méthode ne peut pas disparaitre en java, c’est toute la classe qui est absente du classloader suite à une erreur qui a empêché de reconstruire le JAR ou de recharger le classloader…

@francois une info complémentaire après en avoir rediscuté ce jour :

Le pb apparait de manière “aléatoire” sur une instance de DEV partagée sur laquelle plusieurs personnes font des développements et/ou des clear cache partiels en //. Du coup il y a peut être des effets de bord liés à des compilations concurrentes (dont le synchronize n’est peut être pas assez global ou robuste).

Cela explique sans doute aussi pourquoi on n’arrive pas à reproduire le pb sur une instance en mode mono-designer.

Il y a un LOCK global en V5 dans une même JVM entre la compilation, le clear-cache, la synchro des docs…

La compilation marche très bien sauf si un développeur sauvegarde une erreur Java.

  • Dans ce cas l’ancien JAR est toujours actif, seuls les src et bin sont détruits, le temps qu’il corrige son code
  • Tout le monde voit une erreur lors du “save” dans l’éditeur

Si quelqu’un fait un clear-cache durant ce temps : tous les JAR sont détruits puis recompilés.

Donc votre scénario c’est qq chose comme :

  1. Pierre enregistre String i=2 et part en pause dej
  2. Jacques appelle l’action/méthode = found car l’ancien JAR est toujours là
  3. Paul vide le cache / le jar est supprimé et non reconstruit
  4. Jacques appelle l’action/méthode = not found
  5. Pierre revient de dej et corrige son code et le JAR revient
  6. Jacques doit se reconnecter pour réinstancier ses objets dans le nouveau classloader

Dans tous les cas Pierre Paul Jacques peuvent voir dans les log que le JAR est cassé ou que la compilation a un problème (compile error, no such method , class not found, etc.).

Il y a un feature request là-dessus pour que les développeurs puissent faire des “bugs temporaires” de compilation sans déranger leurs voisins, mais aucune solution simple pour l’instant :

  • Il faudrait un jar/classloader par développeur, mais in fine ça reviendrait à avoir un core-cache simplicité par personne dans un seul tomcat… autant faire N instances
  • Le plus simple serait de ne pas remplacer le JAR si erreur de compilation durant un clearcache, ou quelque chose de cet ordre

.

Après analyse, les JAR sont remplacés si et seulement si la compilation n’a pas d’erreur. Donc en cas de bug dans les sources, les anciens JAR sont bien conservés lors d’un clear-cache complet.

Donc il y a plutôt un problème de concurrence d’accès entre la compilation des classes dans /bin et la fabrication des JAR dans /build.

On va rendre atomic les 2 étapes compilation OK dans bin => annule et remplace des jar.
et on verra si ça corrige le problème de perte de classe temporaire lors d’un développement à plusieurs.

Pour info, on reproduit ce comportement en pré-production alors qu’on ne fait pas de modifications de code ni de clear cache

Le problème disparait bien au redémarage de l’instance et apparait d’une manière aléatoire que nous n’avons pas encore identifié.

Oui nous sommes sur le sujet qu’on n’arrive malheureusement pas à reproduire systématiquement. Mais on a vu ponctuellement passer ce genre de symptôme de manière “aléatoire”, nous c’était plutôt au redémarrage d’une instance (ex: le pb que j’ai eu pendant le webinaire sur les IDEs).

Il y a eu une correction hier sur le core cache lié à une anomalie reproductible (un pb de rechargement des ressources HTML sur clear cache partiel d’un objet externe en zone publique). D’après @francois cette correction peut avoir une portée au delà de ce cas particulier.

Il faudrait donc voir si avec les révisions poussées ce soir vous constatez toujours le pb.

A mon avis cela vient plutôt du code qui ne se recharge pas correctement en cas de changement de class-loader (suite à un clear-cache par exemple qui recompile tout).

Le problème de CAST (d’un autre post) nous donne une autre indication, car normalement il n’y a pas de soucis, on peut tout à fait caster des ObjectDB avec leur héritier Java (dès lors que tout se compile en même temps).

Il faut vérifier si dans une de vos classes (celles qui ne se castent pas entre elles, ou celle où la méthode “disparait”) il y a des méthodes static ou des choses invoquées de façon static : car là une fois monté en mémoire de la JVM il est impossible de les recharger depuis un autre class-loader dynamique (le nouveau code compilé), il faut généralement redémarrer tomcat.

C’est une des raisons pour laquelle on a dû remplacer les GrantHooks historiques (avec des méthodes static) en PlatformHooks mono-instance avec des hook simples (en V5) pour permettre de modifier leurs Hooks sans avoir à redémarrer tomcat dans de nombreux cas de CAST impossibles inter-CL.

Je regarde ce point immédiatement. Du peu que j’ai pu voir en survolant le code rapidement, il n’y a pas de methode static dans notre code a part des constantes déclaré en “static final”.

Je vous tiens au courant dès que j’ai du nouveau, merci à vous.

Nous avons des classe “Shared code” qui on des méthodes utilitaires statiques.

J’imagine que la recommandation serait de les rendre non statiques, mais quel est alors la meilleure pratique pour appeler ces méthodes depuis des instances ObjectDB ?