initRefSelect avec un parent dans un autre module

Bonjour,

J’ai un objet BCSIPerson qui est dans un module A.
J’ai un objet BCSIEAPMApp qui est dans un module B et qui a une FK vers BCSIPerson.

Donc on a module B qui dépend de module A.
Sur la FK, on veut ajouter un filtre sur le type de personne.
Cela est possible en passant par le hook initRefSelect de BCSIPerson.

Ce qui m’embête c’est que du coup, dans le module A, on obtient :

	@Override
	public void initRefSelect(ObjectDB parent) {
		String addSearchSpec = "";
	
		if ( null != parent ) {
			String parentName = parent.getName();
			
			
			if (parentName.equals("BCSIEAPMApp")) {
				addSearchSpec = "pers_type = 'DL'" ;
			}
		}
		
		if ( !"".equals(addSearchSpec) ) {
			AppLog.info(getClass(), "initRefSelect", "ADD this.getSearchSpec=<br/>" + "(" + this.getSearchSpec() + ") AND (" + addSearchSpec + ")", getGrant());
			this.setSearchSpec("(" + this.getSearchSpec() + ") AND (" + addSearchSpec + ")");
		}
	}

On a alors des références à un objet du module B dans le code d’un objet A. Hors nous souhaiterions que le module A soit totalement indépendant des autres puisqu’il s’agit d’un package d’éléments coummuns.
Savez-vous s’il y a un moyen/hook dans l’objet BCSIEAPMApp qui pourrait faire l’équivalent de ce code ?
Nous souhaiterions ainsi que notre module A ne contienne pas de références à des objets d’un autre package.

Cordialement
Amandine TRIDOU

[Platform]
Status=OK
Version=4.0.P24
BuiltOn=2020-09-08 13:58 (revision cc3e1c0a38d7b0549d655541696b9efd34201031)
Encoding=UTF-8
EndpointIP=21.0.9.2
EndpointURL=http://e55490efd12d:8080
TimeZone=Europe/Paris
SystemDate=2020-09-10 14:48:34

Ce n’est pas possible et en terme de maintenance ce n’est pas optimum. mais la dépendance reste textuelle (on teste un nom d’objet) et non pas une classe qui ne serait pas là.

On peut envisager de migrer ce hook pour l’exécuter de l’autre côté (en créant un autre hook pour compatibilité ascendante). On va regarder si c’est envisageable. Je passe le post en change request pour étudier le point.

Comme en Java ou tout modèle relationnel, on peut avoir ce genre de problème de dépendances déclaratives :

  • Référence par nom (et pas par classe) : sur toute librairie commune comme le GrantHooks qui est unique sur la plateforme pour toutes les applications, il parle de groupes et de menus accessibles qui n’y sont pas forcement déclarées : là il faudrait un GrantHooks par module qui viendrait se concaténer au global.

  • Ou des références croisées : si vous avez un cycle ou des références dans les 2 sens (APP référence une Person chef de projet, et une Personne qui aurait une APP préférée)

Dans ce dernier cas, il faut mettre les 2 objets dans le même module (si vous avez paramétré les dépendances de module une des références ne pourra pas être créée). Sinon il faudra importer vos 2 modules sans dépendance en 3 bandes (importer A, puis B, et re-A pour finir le cycle).

Pour mettre le code de l’autre côté, l’objet APP pourrait pré-instancier l’objet “ref_ajax_BCSIPerson” et lui mettre une search-spec au moment du initUpdate de l’application.

Mais il faudra penser à désarmer ce filtre sur tous les autres objets qui l’utilisent, dans les autres modules. Bref en terme de maintenance, c’est pas forcement mieux, avoir un seul initRefSelect permet de centraliser les if/else… au niveau de l’objet que cela concerne = le filtrage des personnes se fait dans l’objet Personne (et pas un peu partout).

De plus votre code ne retire jamais la searchSpec si on est passé par une App en premier, et qu’on passerait par un autre objet référençant une personne (erreur SQL pers_type unknown).

Merci pour votre retour.
Heureusement pour nous, nous avons pas rencontré le cas évoqué avec la persistance du searchSpec. Je surveillerai ce point.
EN vue d’améliorer la qualité de notre code, je pense que je vais crée un objet héritier à BCSIPerson qui lui sera dans le module B.

Je souhaiterai, toutefois (si vous avez le temps bien sûr) voir s’il y a une possibilité d’avoir un hook qui ne s’exécute que lors d’une recherche depuis un élément parent. Par Exemple dans notre cas lorsque l’utilisateur sélectionne un DL. Ce hook permettrait de compléter un searchspec.

Merci d’avance

Oui l’héritage est aussi une bonne option dans ce cas :
vous pouvez créer un objet PersonDL hérité de Person avec un filtre en dur (filtre : t.pers_type=‘DL’), et le mapper avec votre foreign-key de votre objet APP.

L’avantage est de ne pas avoir de code à faire donc sans aucun code à faire, sauf en cas de navigation, si vous souhaitez revenir vers l’objet Person, vous devrez utiliser le getTargetObject dans PersonDL pour rediriger vers Person.

mais bon si PersonDL hérite des hooks de Person, ce n’est pas nécéssaire.

Bonjour,
je remonte le topic pour l’intérêt d’avoir un hook initRefSelect directement dans l’enfant.
En faisant une revue de code pour effectuer la migration Rhino en Java, je suis tombée sur le cas suivant :

BCSIApplication.initRefSelect = function(parent) {
	
	this.setSearchSpec(this.getDefaultSearchSpec());
	var searchSpec = "1=1";

	if (parent != null){
		var parentName = parent.getName();
		
		if (parentName == "BCSIAppLic") {

			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSITechApp','BCSIDesktopApp','BCSIBusnFunctionality','BCSITechFunctionality','BCSIReusableComp','BCSIAppInstance','BCSIAppVersion')";

		}
		if (parentName == "BCSIProjApp" || parentName == "BCSIWorkPackage" || parentName == "BCSIWebSvc" || parentName == "BCSIAppWebSvc" ){
			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSITechApp','BCSIBusnFunctionality','BCSITechFunctionality','BCSIReusableComp','BCSIAppInstance','BCSIAppVersion')";
		}
		if (parentName == "BCSIFlow" || parentName =="BCSIAppSoftware"){
			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSITechApp','BCSIBusnFunctionality','BCSITechFunctionality','BCSIReusableComp','BCSIDesktopApp','BCSIAppInstance','BCSIAppVersion')";
		}
		if (parentName == "BCSIAppCotation"){
			searchSpec="t.app_typo = 'BCSIBusnApp'";
		}
		if (parentName == "BCSIDataConceptUsage" || parentName == "BCSIDataConcept" || parentName == "BCSIAppProductPlatform"){
			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSITechApp','BCSIBusnFunctionality','BCSITechFunctionality')";
		}
		if (parentName == "BCSIDeployment"){
			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSIBusnFunctionality','BCSITechApp','BCSITechFunctionality','BCSIAppInstance','BCSIAppVersion')";
		}
		if (parentName == "BCSIAppScope"){
			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSIBusnFunctionality','BCSIAppInstance','BCSIAppVersion')";
		}
		if (parentName == "BCSIAppFunction"){
			searchSpec="t.app_typo IN ('BCSIBusnApp','BCSIBusnFunctionality','BCSITechApp','BCSITechFunctionality','BCSIReusableComp','BCSIDesktopApp')";
		}
		if (parentName == "BCSIAppContractor" || parentName == "BCSIDataAppli"){
			searchSpec="t.app_typo IN ('BCSIRegroupApp','BCSIBusnApp','BCSIBusnFunctionality','BCSITechApp','BCSIReusableComp','BCSIDesktopApp')";
		}
		
		if ( this.getGrant().hasResponsibility("BCSI-Security-ADMIN") && parent.getName().equals("BCSIAppPersonRMSSI") ) {
			searchSpec="t.app_sub_type in ('RA','AM','FM','TE','IL','PO') and t.app_state in ('IN','ES','PR') and t.app_scope in ('RE','RN') and (t.app_it_support in ('DO','ES','HD') or t.app_it_support like 'ES%')";
		} else
		if ( this.getGrant().hasResponsibility("BCSI-Security-CONTRIB") && parent.getName().equals("BCSIAppPersonRMSSI") ){
			if ( !this.getGrant().hasResponsibility("BCSICollect-Security-RMSSI-CONTRIB") && this.getGrant().hasResponsibility("BCSICollect-Security-RMSSIL-CONTRIB") ) {
				// RMSSI local uniquement -> ne peut créer que des fiches RMSSIL pour applications locales
				searchSpec="t.app_sub_type in ('RA','AM','FM','TE','IL','PO') and t.app_state in ('IN','ES','PR') and t.app_scope in ('RE','RN') and (t.app_it_support in ('DO','ES','HD') or t.app_it_support like 'ES%') and ("+
					BCSIApplicationShared.localAppSQLBribe("BCSIApplication","")+
				")";
			} else if ( this.getGrant().hasResponsibility("BCSICollect-Security-RMSSI-CONTRIB") && !this.getGrant().hasResponsibility("BCSICollect-Security-RMSSIL-CONTRIB") ) {
				// RMSSI central uniquement -> ne peut créer que des fiches RMSSI et RMSSIL pour applications centrales
				searchSpec="t.app_sub_type in ('RA','AM','FM','TE','IL','PO') and t.app_state in ('IN','ES','PR') and t.app_scope in ('RE','RN') and (t.app_it_support in ('DO','ES','HD') or t.app_it_support like 'ES%') and ("+
					BCSIApplicationShared.centralAppSQLBribe("BCSIApplication","")+
				")";
			} else if ( this.getGrant().hasResponsibility("BCSICollect-Security-RMSSI-CONTRIB") && this.getGrant().hasResponsibility("BCSICollect-Security-RMSSIL-CONTRIB") ) {
				// RMSSI central et local -> peut créer des fiches sur applications RMSSI et RMSSIL centrales et locales
				searchSpec="t.app_sub_type in ('RA','AM','FM','TE','IL','PO') and t.app_state in ('IN','ES','PR') and t.app_scope in ('RE','RN') and (t.app_it_support in ('DO','ES','HD') or t.app_it_support like 'ES%')";
			} else {
				// Ni RMSSI ni RMSSIL / Cas non censé se produire
				console.log("[IN BCSIApplication.initRefSelect] STRANGE, NOT RMSSI or RMSSIL, SHOULD NOT OCCURS");
				searchSpec="(1=0/*STRANGE, NOT RMSSI or RMSSIL, SHOULD NOT OCCURS*/)";
			}
		} else
		if ( this.getGrant().hasResponsibility("BCSICollect-Security-ADMIN") && parent.getName().equals("BCSIAppPersonADA")){
			searchSpec="t.app_sub_type in ('RA','AM','FM','TE','IL','PO') and t.app_state in ('IN','ES','PR') and t.app_scope in ('RE','RN') and (t.app_it_support in ('DO','ES','HD') or t.app_it_support like 'ES%')";
		} else
		if ( this.getGrant().hasResponsibility("BCSICollect-Security-CONTRIB") && parent.getName().equals("BCSIAppPersonADA")){
			searchSpec="("+
				"(exists (select 1 from bcsi_app_person ap where ap.app_person_app_id=t.row_id and "+wherePortfolioClause("RMSSI",this.getGrant())+"))"+
				" OR "+
				"(exists (select 1 from bcsi_app_person ap where ap.app_person_app_id=t.row_id and "+wherePortfolioClause("RMSSIL",this.getGrant())+"))"+
			")";
		}
		
		if (parentName == "BCSIAppDatacateg" && parent.getSearchSpec().contains("BCSIHome-Security-ADMIN/BCSI-App-Status-INESPR-Datacateg")||parent.getName().equals("BCSIAppDatacateg_Home_ADMIN")){
			searchSpec="(exists (select 1 from bcsi_app_person ap where ap.app_person_app_id=t.row_id and ap.app_person_role in ('RMSSI','RMSSIS','RMSSIL') ))";
		}
		if (parentName == "BCSIAppDatacateg" && parent.getSearchSpec().contains("BCSIHome-Security-CONTRIB/BCSI-App-Status-INESPR-Datacateg")||parent.getName().equals("BCSIAppDatacateg_Home_CONTRIB")){
			searchSpec="("+
				"(exists (select 1 from bcsi_app_person ap where ap.app_person_app_id=t.row_id and "+wherePortfolioClause("RMSSI",this.getGrant())+"))"+
				" OR "+
				"(exists (select 1 from bcsi_app_person ap where ap.app_person_app_id=t.row_id and "+wherePortfolioClause("RMSSIL",this.getGrant())+"))"+
					"and (t.app_rmssi is null or t.app_rmssi='')"+
				")";
		}
		
		if (parentName == "BCSIFamCoSurvey"){
			searchSpec="(not exists (select 1 from bcsi_fam_co_survey famco where famco.fam_co_survey_app_id=t.row_id) and t.app_state in ('IN','ES','PR'))";
		}
		//BCSICompApp,BCSILicDem,BCSIAppPerson,BCSIDocument,
	}
	
	this.setSearchSpec(searchSpec + " " + "and t.app_state in ('IN','ES','PR')");
	//console.log("[IN BCSIApplication.initRefSelect] this.getSearchSpec=<br/>"+this.getSearchSpec());
};

Je suis consciente que ce code n’est pas optimisé. Cela dit, il prouve que sur des objets centraux complexes, cela devient vite illisible.

Cordialement
Amandine T.

Merci pour votre retour,

Personnellement je trouve plus simple d’avoir centralisés toutes les règles de filtrage de cet objet dans l’objet en question, même s’il y a 50 cas d’usage différents.

  • Le seul argument qui plaide pour un nouveau hook depuis l’appelant parent est le packaging de modules dépendants d’un module commun (qui n’a pas a connaitre ses usages dans des modules liés).
  • Ca rejoint le même besoin au niveau du GrantHooks V4 (devenu PlatformHooks en V5 pour des raisons techniques) et qui est un singleton donc par construction commun, et assez inadapté sur certains hooks qui devrait être par module (ex : les menus/domaines habilités)

On va traiter ça dans une release V5.