User exécute les hook de son fils

Bonjour
Nous avons un objet BCSIPerson qui hérite de User et qui possède des attributs additionnels.
BCSIPerson possède du code JAVA initList et initUpdate qui change les propriétés de certains champs (visibilité/updatable).
Lorsque nous livrons le code de BCSIPerson via import XML puis clear cache global, aucun soucis.
On se connecte et on va ensuite sur la page d’administration Simplicité des utilisateurs, on observe des erreurs dans les logs comme quoi il a tenté d’exécuter le initUpdate de BCSIPerson et que l’objet USer ne possède pas le champ xxx (ce qui est normal puisque xxx est un champ de BCSIPerson).
Il faut alors aller sur l’objet User et cliquer sur “Vider le cache” et les erreurs ne s’affichent plus.

Déclaration BCSIPerson

Code BCSIPerson

package com.simplicite.objects.BCSIModule_OrgItems;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.simplicite.commons.BCSIModule_Commons.BCSIArcaToolbox;
import com.simplicite.commons.BCSIModule_Commons.BCSIGroupEnum;
import com.simplicite.util.*;
import com.simplicite.util.tools.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.HttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import org.json.JSONObject;


/**
 * Business object BCSIPerson
 */
public class BCSIPerson extends com.simplicite.objects.System.User {

	private static final long serialVersionUID = 1L;

	@Override
	public void initList(ObjectDB parent) {
		super.initList(parent);
		manageField();
	}

	@Override
	public void initCreate() {
		super.initCreate();
		manageField();
	}

	@Override
	public void initUpdate() {
		super.initUpdate();
		manageField();
	} 

	private void manageField() {
				
		this.getField("PersonAPI").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonStructuralUnit").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonTitleOrPositionFR").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonTitleOrPositionEN").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonCostCenter").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonAccountingCenter").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonManager").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonManagementDomain").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonHRDomain").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonJobFR").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonJobEN").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonStructureAttachmentFR").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonStructureAttachmentEN").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonLastADPUpdateDate").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonLastADPSynchroDate").setUpdatable(ObjectField.UPD_READ_ONLY);

		if  (this.getGrant().hasResponsibility(BCSIGroupEnum.ADMIN.getCode())) {
			this.getField("PersonAPI").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonStructuralUnit").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonTitleOrPositionFR").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonTitleOrPositionEN").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonCostCenter").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonAccountingCenter").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonManager").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonManagementDomain").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonHRDomain").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonJobFR").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonJobEN").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonStructureAttachmentFR").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonStructureAttachmentEN").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonLastADPUpdateDate").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonLastADPSynchroDate").setUpdatable(ObjectField.UPD_ALWAYS);
		}
	}
	
	public void refreshUserList(List<String> list) {
	}
}

J’importe cette classe du DEV vers la RECETTE en y ajoutant un AppLog
XML

<?xml version="1.0" encoding="UTF-8"?>
<simplicite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.simplicite.fr/base" xsi:schemaLocation="http://www.simplicite.fr/base https://www.simplicite.io/resources/schemas/base.xsd">
<object>
	<name>ObjectInternal</name>
	<action>UPSERT</action>
	<data>
		<obo_name>BCSIPerson</obo_name>
		<obo_dbtable>m_user</obo_dbtable>
		<obo_class/>
		<obo_script_id><![CDATA[DATA:BCSIPerson.java:package com.simplicite.objects.BCSIModule_OrgItems;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.simplicite.commons.BCSIModule_Commons.BCSIArcaToolbox;
import com.simplicite.commons.BCSIModule_Commons.BCSIGroupEnum;
import com.simplicite.util.*;
import com.simplicite.util.tools.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.HttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import org.json.JSONObject;


/**
 * Business object BCSIPerson
 */
public class BCSIPerson extends com.simplicite.objects.System.User {

	private static final long serialVersionUID = 1L;

	@Override
	public void initList(ObjectDB parent) {
		super.initList(parent);
		manageField();
		AppLog.info("Test modification class", getGrant());
	}

	@Override
	public void initCreate() {
		super.initCreate();
		manageField();
	}

	@Override
	public void initUpdate() {
		super.initUpdate();
		manageField();
	} 

	private void manageField() {
				
		this.getField("PersonAPI").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonStructuralUnit").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonTitleOrPositionFR").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonTitleOrPositionEN").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonCostCenter").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonAccountingCenter").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonManager").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonManagementDomain").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonHRDomain").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonJobFR").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonJobEN").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonStructureAttachmentFR").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonStructureAttachmentEN").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonLastADPUpdateDate").setUpdatable(ObjectField.UPD_READ_ONLY);
		this.getField("PersonLastADPSynchroDate").setUpdatable(ObjectField.UPD_READ_ONLY);

		if  (this.getGrant().hasResponsibility(BCSIGroupEnum.ADMIN.getCode())) {
			this.getField("PersonAPI").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonStructuralUnit").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonTitleOrPositionFR").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonTitleOrPositionEN").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonCostCenter").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonAccountingCenter").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonManager").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonManagementDomain").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonHRDomain").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonJobFR").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonJobEN").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonStructureAttachmentFR").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonStructureAttachmentEN").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonLastADPUpdateDate").setUpdatable(ObjectField.UPD_ALWAYS);
			this.getField("PersonLastADPSynchroDate").setUpdatable(ObjectField.UPD_ALWAYS);
		}
	}
	
	public void refreshUserList(List<String> list) {
	}
}]]></obo_script_id>
		<obo_usets>1</obo_usets>
		<obo_nosearch>1</obo_nosearch>
		<obo_comment/>
		<obo_type>O</obo_type>
		<obo_searchspec><![CDATA[t_row_module_id.mdl_name like 'BCSI%']]></obo_searchspec>
		<obo_delspec/>
		<obo_exportorder>1</obo_exportorder>
		<obo_distinct>0</obo_distinct>
		<obo_indexable>1</obo_indexable>
		<obo_groupby>0</obo_groupby>
		<obo_dfltref/>
		<obo_template_id.tpl_name>Person</obo_template_id.tpl_name>
		<obo_cache>D</obo_cache>
		<obo_copy>1</obo_copy>
		<obo_export>1</obo_export>
		<obo_pagine>1</obo_pagine>
		<obo_srh_predef>1</obo_srh_predef>
		<obo_selrow>1</obo_selrow>
		<obo_updall>1</obo_updall>
		<obo_delall>1</obo_delall>
		<obo_listsearch>1</obo_listsearch>
		<obo_list_edit>N;L;I;E</obo_list_edit>
		<obo_useform>1</obo_useform>
		<obo_title/>
		<obo_icon/>
		<obo_refcount>0</obo_refcount>
		<obo_tree>0</obo_tree>
		<obo_viewmode>V</obo_viewmode>
		<obo_historic>1</obo_historic>
		<obo_printable>0</obo_printable>
		<obo_followlink>1</obo_followlink>
		<obo_mergeable>1</obo_mergeable>
		<obo_social/>
		<obo_rowid_id.fld_name/>
		<obo_extend_id.obj_name>User</obo_extend_id.obj_name>
		<row_module_id.mdl_name>BCSIModule_OrgItems</row_module_id.mdl_name>
		<obo_btn_reload>P</obo_btn_reload>
		<obo_btn_prefs>P</obo_btn_prefs>
		<obo_btn_del>P</obo_btn_del>
		<obo_btn_copy>P</obo_btn_copy>
		<obo_btn_export>P</obo_btn_export>
		<obo_btn_listadd>1</obo_btn_listadd>
		<obo_btn_listedit>1</obo_btn_listedit>
		<obo_btn_listupsert/>
		<obo_btn_updall>P</obo_btn_updall>
		<obo_btn_delall>P</obo_btn_delall>
		<obo_btn_merge>P</obo_btn_merge>
		<obo_btn_save>1</obo_btn_save>
		<obo_btn_saveclose>1</obo_btn_saveclose>
		<obo_btn_close>1</obo_btn_close>
		<obo_tray>1</obo_tray>
		<obo_dashboard>1</obo_dashboard>
		<obo_prefix/>
		<obo_search_ts/>
	</data>
</object>
</simplicite>

Après un clear cache, je vais sur la page de détail d’un utilisateur, j’obtiens l’erreur suivante

.

Evidemment quand je vais sur la page d’édition d’une BCSIPerson, je n’ai pas d’erreur.

Il faut que j’aille Vider le chache de l’objet User pour que les erreurs disparaissent.

C’est comme si lors de l’import mon code était associé à l’objet User. (Association “fantôme” car le champ code source de User est bien vide).

Je reproduis ce bug à chaque livraison.
Cordialement
Amandine T.

[Platform]
Status=OK
Version=4.0.P24
BuiltOn=2020-09-30 12:05 (revision 5a820e8be619728c3675ce2fc5d5beee3afe294a)
Encoding=UTF-8
EndpointIP=21.0.15.4
EndpointURL=http://3acff2758c69:8080
TimeZone=Europe/Paris
SystemDate=2020-10-28 23:01:56

Etrange,

  • peut-on avoir le code de User si vous en avez mis ?
  • et du paramètre système OBJECT_MANAGEMENT_USER (qui permet de dire quel objet est utilisé quand un user click sur son profil) ?

On dirait que User hérite de BCSIPerson quelque part.

Bonjour
il n’y a pas de code sur User. Nous avons pensé aussi à une référence mais lorsque l’on exporte User, aucune référence à BCSIPerson.
User.xml (85.5 KB)

Ok on va essayer de reproduire ça alors…

Non reproduit sur une V4 et une V5 à jour.
J’ai créé un User2 qui hérite de User avec un champ en plus user_ext et le code suivant :

package com.simplicite.objects.Application;

import java.util.*;
import com.simplicite.util.*;
import com.simplicite.util.tools.*;

/**
 * Business object User2
 */
public class User2 extends com.simplicite.objects.System.User {
	private static final long serialVersionUID = 1L;
	
	@Override
	public void initList(ObjectDB parent) {
		ObjectField f = getField("user_ext");
		AppLog.info(User2.class, "initList", ""+f, getGrant());
	}
}

En partant d’une instance vide, en important cet objet + vider la cache :

  • L’info s’affiche uniquement sur l’objet User2, avec la défintion du champ étendu
  • Et User n’a aucun problème, et ne voit pas du tout le champ ni le code.

C’est impossible d’hériter à l’envers en Java, ça voudrait dire que l’invocation est dynamique comme en Rhino. Et clairement Simplicité ne référence jamais vos objets.

Mettez un try/catch pour ne pas sortir en erreur, car je ne vois aucune explication sans chercher les références à “User” dans tout votre projet, ou une erreur de chargement de votre objet et qui passerai dans un mode dégradé où “fils=parent”. Mais d’un point de vue Java c’est impossible si les JAR compilés et les modules sont bien chargés (pas de zombies d’une version précédente suite à un import de module en erreur…).

Merci François pour ton analyse.
Comme élément de contexte, j’ajouterai qu’un des hooks postXXX de l’objet User a été auparavant surchargé avec du code Rhino qui a été désinvesti depuis. Le code en question instanciait en effet l’objet BCSIPerson pour déclencher une action dessus suite à la création du compte d’un nouvel utilisateur.

La piste Rhino qui appelle les méthodes dynamiquement me semble une meilleure explication à cet héritage “inversé” (User instancie Person qui instancie User…). Il ne faut jamais coder directement sur un objet System car les effets sont imprévisibles entre ce que fait Simplicité (en java) et du code ajouté (Rhino).

  1. Il faut vérifier que l’import de votre module se passe bien sans aucune erreur même mineure, pour qu’il y ait bien le “diff” final dans les log qui élague les paramétrage obsolètes, sinon il restent effectivement sur l’objet (le script Rhino sur User doit bien avoir disparu après import de module).

  2. Ensuite c’est effectivement un simple pb de cache à vider, le temps que ce hook Rhino disparaisse complètement de la mémoire. Votre procédure de contournement de devoir vider le cache du User explicitement devrait être temporaire à votre version.

  3. Mettez un try/catch pour traper l’erreur comme un warning dans votre méthode manageField.