Architecture des préférences TBX et RCP

Objectif

Améliorer l'architecture des préférences et propriétés de la Toolbox et de la RCP :

  • faciliter l'interopérabilité entre les préférences de la Toolbox et celles de la RCP
  • faciliter l'ajout de nouvelles préférences
  • faciliter l'édition de préférences
  • faciliter la définition des valeurs par défaut des préférences lorsqu'elles n'existent pas dans le fichier des préférences.
  • préparer le système à la division en plugins des projets TBX et RCP

Je pense [SJ] que cette phase doit être faite avant, voire en même temps, que le découpage en plugins des projets TBX et RCP.

État de la plateforme

  • la Toolbox utilise un mécanisme basé sur la classe Properties et qui regroupe toutes les préférences liées à la Toolbox
  • la RCP utilise le système d'Eclipse/JFace basée sur la classe ScopedPreferenceStore et qui récupère et copie les préférences de la Toolbox
  • le charts engine utilise un mécanisme basé sur la classe Properties et qui contient et initialise les préférences qui lui sont propres
  • lors du premier lancement de TXM, si le fichier org.txm.rcpapplication.prefs n'existe pas, TXM base les valeurs par défaut des préférences sur le fichier install.prefs

L'utilisation de deux systèmes différents de gestion des préférences pour la TBX et la RCP complique énormément l'ajout, l'édition et la définition des valeurs par défaut des préférences. Il faut définir des constantes dans la TBX, les redéfinir dans la RCP, copier les préférences d'un niveau vers l'autre, etc.

D'autre part, il faut aussi définir les valeurs par défaut des nouvelles préférences dans le fichier install.prefs, ce qui complexifie encore. Par exemple si un fichier org.txm.rcpapplication.prefs existe mais que la préférence n'existe pas, sa valeur par défaut est définie en dur dans le code mais si le fichier org.txm.rcpapplication.prefs n'existe pas les valeurs par défaut doivent être définies dans install.prefs. Pour ce point j'aurais tendance [SJ] à proposer de ne plus utiliser le fichier install.prefs et de tout coder en dur, ce qui supprimerait déjà un endroit supplémentaire de gestion des prefs générateur d'oubli et d'erreurs.

Seule la RCP est capable de sauvegarder les préférences. Elles sont sauvegardées dans le fichier “org.txm.rcpapplication.prefs” où “org.txm.rcpapplication” est en faite l'ID de plugin de la RCP. La Toolbox autonome (comme dans le portail) ne fait que lire un fichier properties.

Par ailleurs, les valeurs par défaut des préférences RCP ne sont pas systématiquement définies, ainsi “Restore default” sur une page de préférence RCP fonctionne mal.

Méthode

  • définir le niveau de chaque préférence : TBX ou RCP
    • pour rappel, pour une meilleure compatibilité du charts engine avec le Portail et que la TBX puissent fonctionner correctement de manière autonome, il faudrait déplacer les préférences liées au rendu des graphiques du niveau RCP vers le niveau TBX
  • définir les classes ou méthodes partagées entre les différents plugins
    • MD : la classe TXMPreferences existe déjà, mais elle ne permet de récupérer que les préférences sauvées dans le scope de la RCP (et donc pas des plugins)
  • déplacer vers TBX les préférences RCP qui doivent être liées à la Toolbox

Anciennes notes :

  • Une solution possible serait que la TBX utilise un Store de préférence et que la RCP aille chercher une préférence dans le Store de la TBX si elle ne trouve pas de valeur pour une clé de préférence.
    • MD : faut voir si on aura besoin d'une hiérarchie de recherche (ex : chercher d'abord dans un plugin , puis RCP puis TBX)
  • Ou alors un partage de store (il y aurait donc un Store par plugin)
    • MD : pour moi un partage de store, fait qu'il y a un seul store ?
      • SJ : en fait, c'est une citation de toi :D

Questions :

  • Est-ce qu'un store par plugin signifie forcément un fichier de préférence par plugin ?
    • MD : oui
      • SJ : finalement après tests, non on peut utiliser un seul fichier, en revanche les Store sont dans le bundle JFace donc liés à l'UI. Il faut plutôt utiliser IEclipsePrefereces.
  • Ça semble être le cas dans Eclipse + plugins installés mais ce n'est peut-être pas forcément pratique ?
    • MD : j'imagine que ça peut être pratique (fichiers moins volumineux à lire, moins de risque de casser le fichier ?) quand les plugins sont très nombreux comme dans Eclipse.
      • SJ : effectivement

Avec la séparation par plugins, il y aura a priori de toute façon un Store par plugin ? Et le plugin pourra alors se charger d'initialiser lui-même ses propres préférences et de définir les valeurs par défaut.

  • MD : un plugin peut lire, écrire, définir des valeurs par défaut dans le store de la RCP (ou le futur store de la TBX)
  • MD : dans tous les cas, c'est le plugin qui définira ses valeurs par défaut. Actuellement dans TXM, c'est un fichier qui définit les valeurs par défaut, mais on peut très bien faire ça dans un PreferenceInitializer (API Eclipse RCP)
    • Oui après tests, je pense que c'est la solution à adopter, voir la rubrique “Solution” en bas de page
  • attention il faut que la transition vers la nouvelle architecture soit compatible avec le système de mise à jour automatique implémenté depuis TXM 0.7.5

Avancement dans l'élaboration de la solution

Solution

TODO: Reste à définir le nom de fichier des prefs globales/partagées, je propose d'utiliser directement Platform.getProduct().getId() pour récupérer dynamiquement le nom du fichier global/partagé des préférences dans chaque plugin. Reste aussi à définir si les préférences des plugins optionnels doivent être stockées dans le fichier global des prefs ou bien dans des fcihiers à part. Je propose de les stocker dans des fichiers à part en utilisant l'id du bundle comme preference node qualifier, ne connaissant pas le comportement lors de la désinstallation d'une plugin optionnel (à mon avis les prefs restent dans le fichier).

Première proposition, testée avec le plugin WordCloud, tout fonctionne.

Dans la TBX (ou tout plugin de type non UI) :

  • ajouter l'extension “org.eclipse.core.runtime.preferences” (pour info la classe “org.eclipse.core.runtime.Preferences” est deprecated mais pas l'extension “org.eclipse.core.runtime.preferences”)
  • créer un nouveau noeud “initializer”
  • créer des constantes statiques avec les noms des prefs (ces noms seront notamment utilisés dans le fichier .prefs). Voir s'il y a des recommandations d'Eclipse pour les noms des prefs car j'ai vu que certains plugins Eclipse utilisent parfois le nom du bundle, ce qui est peut-être pas mal (ex. org.txm.tbx.wordcloud.maxWords) ? Exemple pour le plugin WordCloud :
public static final String PREFERENCE_NODE = Platform.getProduct().getId(); // pour utiliser le fichier global/partagé ou bien :
public static final String PREFERENCE_NODE = "org.txm.tbx.wordcloud"; // pour sauver les prefs dans un fichier org.txm.tbx.wordcloud.prefs
public static final String MAXWORDS = "wordcloud_maxwords"; //$NON-NLS-1$
public static final String FMIN = "wordcloud_fmin"; //$NON-NLS-1$
public static final String ROT = "wordcloud_rotper"; //$NON-NLS-1$
public static final String RANDOMCOLOR = "wordcloud_randomcolor"; //$NON-NLS-1$
  • remplir le DefaultScope.INSTANCE avec les valeurs par défaut dans “public void initializeDefaultPreferences()”. Exemple pour le plugin WordCloud :
@Override
public void initializeDefaultPreferences() {
	Preferences defaultPreferences = DefaultScope.INSTANCE.getNode(PREFERENCE_NODE);
	
	defaultPreferences.put(MAXWORDS,"50");
	defaultPreferences.put(FMIN, "2");
	defaultPreferences.put(ROT, "10");
	defaultPreferences.put(RANDOMCOLOR, "false");
}
  • les valeurs des prefs sont récupérables partout en utilisant Platform.getPreferencesService().getString(WordCloudPreferencesInitializer.PREFERENCE_NODE, MAXWORDS, ””, null); (getInt(), getBoolean(), etc.)
  • en utilisant le IPreferencesService retourné par Platform.getPreferencesService(), les valeurs retournées sont celles du fichier .prefs lié au node si la pref existe dedans (donc du ConfigurationScope.INSTANCE), sinon celle du DefaultScope.INSTANCE

Dans la RCP (ou tout plugin de type UI)

  • ajouter l'extension “org.eclipse.ui.preferencePages”
  • créer un nouveau noeud “page”
  • dans la page créer une méthode (convenience method pour récupérer un store depuis le Handler par exemple) :
public static ScopedPreferenceStore getNewPreferenceStore()	{
	return new ScopedPreferenceStore(ConfigurationScope.INSTANCE, WordCloudPreferencesInitializer.PREFERENCE_NODE);
}
  • définir le preference store dans le constructeur ou mieux dans init()
setPreferenceStore(getNewPreferenceStore());

En utilisant tout ça voici ce qu'il se passe :

  • les prefs n'existent pas dans le fichier .prefs si leur valeur ne diffère pas de la valeur par défaut. Elles sont même re-supprimées du fichier si on les repasse à la valeur par défaut.
  • la fonctionnalité “Restaurer les prefs par défault” des pages de pref fonctionne bien et récupère les valeurs du DefaultScope.INSTANCE
  • la valeur de PREFERENCE_NODE, par exemple dans “DefaultScope.INSTANCE.getNode(PREFERENCE_NODE)” définit le nom du fichier .prefs qui sera utilisé. Si on utilise le bundle id on aura par exemple un fichier “org.txm.tbx.wordcloud.prefs”

Au sujet de l'utilisation de Platform.getProduct().getId(), attention si on utilise plusieurs products.

TODO: Il faudrait définir nos propres extensions points pour TXMPreferenceInitializer et TXMPreferencePage notamment car du code peut être mutualisé, ex. “public static ScopedPreferenceStore getNewPreferenceStore()”. Ex. org.txm.tbx.preferences et org.txm.rcp.preferencePage

Voir également la classe existante /org.txm.rcp/src/main/java/org/txm/rcpapplication/TxmPreferences.java une partie du code est à reprendre et à mettre dans une classe abstraite mais au niveau de la TBX, pour les getInt(), getString(), etc. ex. : public abstract TXMPreferencesInitializer extends AbstractPreferenceInitializer - public final String PREFERENCE_NODE = “org.txm.tbx.wordcloud”; - getInt(), getString(), etc.utilisant Platform.getPreferencesService().getString(REFERENCE_NODE, preferenceName, ””, null). Ceci implique de créer un plugin supplémentaire org.txm.tbx.preferences pour qu'il soit utiliser par le host TBX mais aussi par les plugins de contribution.

Voir https://www.eclipse.org/forums/index.php/t/1082107/ et https://wiki.eclipse.org/FAQ_What_is_a_preference_scope%3F

État de l'art

La classe TXMPreferences utilise l'InstanceScope (et non pas le ConfigurationScope) et c'est ce scope qui est exporté lorsque l'on utilise l'export des préférences dans TXM.

Prototypes

Version finale

Recette

Protocole de test

Alpha

Beta

État courant

public/preferences_system.txt · Dernière modification: 2017/01/19 11:49 par sebastien.jacquot@univ-fcomte.fr