Integration à JNDI

Cette page décrit comment JEZXmlConfig s'intégre avec JNDI.

Fournisseur de service JNDI spécifique à JEZXmlConfig

JEZXmlConfig possède son propre fournisseur de service JNDI implémenté accessible à partir de la classe net.sourceforge.jezxmlconfig.jndi.spi.XmlConfigInitCtxFactory.
C'est une implémentation simple avec un espace de noms hiérarchique (pas de fédération). Ceci implique qu'un objet qui veut accéder à une configuration depuis ce fournisseur de service JNDI doit se trouver sur la même machine.
Dans une version future, ce fournisseur de service JNDI sera étoffé. De plus, un client LDAP sera implémenté pour permettre l'accès à des configurations depuis un serveur LDAP.

Cette implémentation utilise la valeur de la propriété système "java.naming.provider.url" pour déterminer le répertoire racine de sa zone de stockage.
Cette propriété doit contenir une URI au format format "jezxmlconfig:/path" où path désigne la racine de la zone de stockage. Par exemple, sous Windows vous pouvez utiliser "jezxmlconfig:/C:/DATA/MyConfRootDir", et sous Unix "jezxmlconfig:/DATA/MyConfRootDir".
Sous ce répertoire, les configurations disponibles sont stockées dans des fichiers textes (au format XML), et peuvent être rangées dans des sous-répertoires.

Les noms de fichiers (avec le chemin absolu par rapport à la racine de stockage) correspondent aux noms JNDI.
Par exemple, si la racine de stockage est "/DATA/myConfRootDir" et qu'une configuration a pour nom JNDI "subdir/foo.xml", elle sera stockée dans le fichier "/DATA/myConfRootDir/subdir/foo.xml".

Le diagramme suivant décrit cet exemple de structure dans le fournisseur de service JNDI de JEZXmlConfig :

Remarque: Pour des raisons de sécurité, il est impossible d'accéder un chemin de niveau plus élevé que la racine de stockage.

Accès client à JNDI

Un programme qui utilise JNDI avec JEZXmlConfig doit définir la propriété système "java.naming.provider.url" pour permettre au fournisseur de service JNDI spécifique à gérer sa zone de stockage. Ceci peut être fait en ajoutant l'option suivante sur la ligne de commande :

java -Djava.naming.provider.url=jezxmlconfig:/DATA/myConfRootDir mon.package.MaClassePrincipale ...

Pour obtenir une configuration, il suffit d'appeler la bonne méthode (à la place de getInstance()) :

    XmlConfig config;
    try {
        config = XmlConfig.jndiLookup("foo.xml");
    }
    catch(XmlConfigException xce) {
        throw MyApplicationException("Cannot access 'foo.xml' configuration: " + xce.getMessage());
    }
    ...
Remarques:
  1. La méthode jndiLookup(jndiName) charge une configuration et la mémorise avec la clef d'accès "jndiName".
    Cela implique qu'après cet appel, il est possible d'invoquer getInstance(jndiName) pour re-obtenir la même instance de configuration à la condition que votre code dépende du même "class loader".
    Attention: Ceci est fortement déconseillé dans un environnement J2EE car rien ne garanti qu'un EJB soit lancé par le même "class loader", et l'appel à getInstance() risque de ne pas fonctionner. Dans ce cas faites toujours appel à la méthode jndiLookup(jndiName).
  2. Si vous appelez jndiLookup(jndiName) une seconde fois, la configuration rechargée écrasera la précedente stockée avec la clef d'accès "jndiName".
    Si vous voulez juste re-obtenir la configuration précédement chargée et que vous êtes certain de dépendre du même "class loader", utilisez la méthode getInstance(jndiName).

Il est aussi possible de lister les configurations disponibles depuis JNDI:

    List configList; // Contiendra les noms JNDI des configurations disponibles (Objets de type String).
    try {
        configList = XmlConfig.jndiList();
    }
    catch(XmlConfigException xce) {
        throw MyApplicationException("Cannot access configuration list: " + xce.getMessage());
    }
    ...

Accès bas niveau à JNDI

Si un programme veut communiquer avec JNDI à un bas niveau, il doit spécifier la classe de fabrication du context initial du fournisseur de service JNDI spécifique à JEZXmlConfig.

Ceci peut être fait de deux façons:

  1. En ajoutant les options "-Djava.naming.factory.initial=net.sourceforge.jezxmlconfig.jndi.spi.XmlConfigInitCtxFactory"
    et "-Djava.naming.provider.url=jezxmlconfig:/DATA/myConfRootDir" sur la ligne de commande, et en obtenant le contexte initiale de façon simple:
        Context ctx;
        try {
            ctx = new InitialContext();
        }
        catch(NamingException ne) {
            throw MyApplicationException("Cannot get JNDI initial context (" + ne.getClass().getName() +
                                         "): " + ne.getMessage());
        }   
  2. En spécifiant cette propriété lors de la recherche du contexte initial:

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "net.sourceforge.jezxmlconfig.jndi.spi.XmlConfigInitCtxFactory");
        env.put(Context.PROVIDER_URL, "jezxmlconfig:/DATA/myConfRootDir");
        Context ctx;
        try {
            ctx = new InitialContext(env);
        }
        catch(NamingException ne) {
            throw MyApplicationException("Cannot get JNDI initial context (" + ne.getClass().getName() +
                                         "): " + ne.getMessage());
        }   

Ensuite, il peut faire n'importe quelle opération JNDI sur le contexte obtenu.
Par exemple:

    XmlConfig config;
    try {
        config = (XmlConfig)ctx.lookup("foo.xml");
    }
    catch(NamingException ne) {
        throw MyApplicationException("Cannot access 'foo.xml' configuration (" +
                                     ne.getClass().getName() + "): " + ne.getMessage());
    }

Dans JNDI, chaque context correspond à une sous-répertoire dans la zone de stockage.

Voici un tableau récapitulatif des actions menées par le fournisseur de service JNDI de JEZXmlConfig :

méthode JNDI Effet
lookup Recherche une configuration (objet XmlConfig) ou un sous-répertoire (objet java.naming.Context).
lookupLink Idem à lookup (Les liens symboliques ne sont pas supportés).
bind Ajoute une nouvelle configuration dans la zone de stockage du fournisseur de service JNDI de JEZXmlConfig.
rebind Remplace une configuration existante.
unbind Détruit une configuration.
rename Renomme ou déplace une configuration.
Remarque: Si vous voulez déplacer des configurations, il faut que tous les sous-répertoires de la zone de stockage soient dans le même filesystem.
list Liste un context: i.e. Liste les noms et classes des objets (configurations) et des sous-contextes (sous-répertoires) qui se trouvent dans le contexte courant.
listBindings Idem à list, mais recherche en plus les objects.
createSubcontext Crée un sous-contexte dans le contexte courant: i.e. Crée un sous-répertoire.
destroySubcontext Détruit un sous-contexte dans le contexte courant: i.e. Détruit un sous-répertoire.
getNameInNamespace Donne le chemin absolu du répertoire correspondant au contexte courant. Par exemple, si le contexte courant est "subdir" dans la racine de la zone de stockage, la valeur de retour pourra être "C:\DATA\myConfRootDir\subdir" sous Windows, et "/DATA/myConfRootDir/subdir" sous Unix.