Lire et écrire sur des annuaires LDAP avec des agents Lotus Notes


Pour effectuer ces d'opérations depuis Lotus Notes, j'utilise des agents Java sur mon annuaire.

Voici le code simplifié de cet agent. Il renseigne, sur un autre annuaire LDAP (par exemple l'annuaire LDAP Windows)
le champ "OU", en y mettant la valeur du champ "Service" de l'annuaire Lotus Notes, en me basant sur la clé "Nom-Prénom".


import lotus.domino.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Map;
import java.lang.String;

public class LectureLDAP extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
Log log = session.createLog("EcritureNotesVersLDAP");
log.openFileLog("d:/Lotus/AMgr_Log/EcritureLDAP_Telephonique.txt");

AgentContext agentContext = session.getAgentContext();

Database db;
db = agentContext.getCurrentDatabase();

log.logAction("Démarrage de l'agent");

java.util.Hashtable env = new java.util.Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://NomDuServeurLDAP:389/");
// ici j'indique que je me connecte avec authentification : user + mot de passe env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=Compte LDAP,o=directory"); // user
env.put(Context.SECURITY_CREDENTIALS, "MotDePasse"); // mot de passe

DirContext ctx = new InitialDirContext(env);

log.logAction("Connexion LDAP ok");

ModificationItem[] mods = new ModificationItem[1];

View vue = db.getView("(Personnes)");
Document doc = vue.getFirstDocument();

while (doc != null)
{
String nom = doc.getItemValueString("LastName");
String prenom = doc.getItemValueString("FirstName");
String identif = prenom + " " + nom ;
String service = doc.getItemValueString("ServiceL");

NamingEnumeration answer;
String recherche = "o=directory";
String filtre = "(uid=" + identif + ")";
SearchControls ctls = new SearchControls();
// Pour que la recherche porte également sur les sous-niveaux du noeud LDAP
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
log.logAction("Recherche avec filtre = " + filtre + " sur la base " +
recherche); answer = ctx.search( recherche, filtre, ctls);

if (answer.hasMore()) {
try {
// Modification du compte LDAP
Attributes attrs = sr.getAttributes();
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new
BasicAttribute("ou", service)); log.logAction("J'essaie de modifier " + name + " pour mettre ou=" + service); ctx.modifyAttributes(name, mods);
log.logAction("ok !");
}
catch (Exception e4)
{
log.logAction("Erreur lors de la tentative de modification de " + filtre +
" : " + e4);
}

}
else
{
log.logAction("Impossible de trouver "+ prenom + " " + nom + " dans l'annuaire LDAP. Pas de modification effectuée");
}


doc = vue.getNextDocument(doc);

} // fin boucle principale while

log.logAction("Fin normale de l'agent");


} catch(Exception e) { system.out.println("Erreur : " + e); } // fin try
} // fin main
} // fin classe



Le 30/01/2006 - Benoît Colin

 

Comment superviser l'exécution de tous les agents plannifiés d'un serveur


Difficile, avec Lotus Notes, d'avoir un aperçu général des exécutions de tous les agents planifiés se trouvant sur un serveur. Il faut ouvrir les bases une par une, ouvrir les agents plannifiés un par un pour pouvoir voir quand un agent plannifier doit s'exécuter.

Mon souhait était d'avoir une vision globale de tous les agents du serveur et de leur plannification, afin de me rendre compte des pics de charges liées à l'exécution de ces agents.

Cela a été possible grace à... un agent LotusScript plannifié. Appelons-le "Agent Audit".
Son principe est simple : cet agent parcours toutes les bases du serveur ; pour chacune des bases, il examine les agents qui sont de type "plannifiés"...

Malheureusement, les classes LotusScript ne nous permettent pas d'accèder aux propriétés de plannification d'un agent (c'est à dire si il est exécuté quotidiennement, hebdomadairement, à quelle heure, à quel intervalle...)

Par contre, on peut accèder à une autre information, qui nous sera bien utile : la dernière date d'exécution de l'agent !

Agent.LastRun


Je plannifie mon "Agent Audit" pour qu'il s'exécute toutes les 10 minutes.
Ainsi, régulièrement, cet agent récupére la dernière date d'exécution de tous les agents plannifiés. Ces informations sont enregistrées dans les documents Notes (Date-Heure, Nom de la base Notes, Nom de l'agent, Dernière date d'exécution).

Bon, trèves de bla-bla, voici le code :

On Error Goto erreur

Dim session As New NotesSession
Dim currentdb As NotesDatabase
Dim database as Notesdatabase
Dim view As NotesView
Dim doc As NotesDocument

Set currentdb = session.CurrentDatabase

Dim dbdir As New NotesDbDirectory("MonServeur/SVR/MonDomaine")

Set database = dbdir.GetFirstDatabase(DATABASE)

While Not database Is Nothing

TentativeOuverture=True
Call database.Open ("", "")
TentativeOuverture=False

agents = database.Agents

If Not Isempty(agents) Then

Forall a In agents
If a.trigger = TRIGGER_SCHEDULED And a.HasRunSinceModified = True Then

Set doc = db.CreateDocument
doc.form = "DateExecAgent"
doc.Base = database.Title
doc.BaseFichier = ReplaceString(database.FilePath, "\", "/")
doc.Agent = a.Name
doc.DerniereDateExecution = a.LastRun
doc.Serveur = a.ServerName
doc.BaseAgent = ReplaceString(database.FilePath, "\", "/") + "-" + a.Name
Call doc.Save (True, True)

Set doc = db.CreateDocument
doc.form="Agent"
doc.BaseAgent = ReplaceString(db2.FilePath, "\", "/") + "-" + a.Name
Call doc.Save(True, True)

End If
End Forall
End If

BaseSuivante :
Set database = dbdir.GetNextDatabase

Wend

Exit Sub

erreur :

If TentativeOuverture = True Then
Set nlog = db.createdocument
nlog.form="Log"
nlog.Body = "Impossible d'ouvrir la base " & db2.Title & " : " & Error & " ligne " & Str(Erl)
Call nlog.Save (True, True)

Resume BaseSuivante
End If

Messagebox(Error & " à la ligne " & Str(Erl))



Le 27/01/2006 - Benoît Colin

 

Une vue Lotus Notes 100% html mais néanmoins catégorisée



Le problème
Sous Lotus Notes, l'utilisation de la propriété "Traiter le contenu de la vue comme du code html" interdit en principe d'utiliser les fonctions de déployer-condenser de catégories lors de la consultation de la vue avec le navigateur. En effet, Domino ne génére pas de boutons permettant de déployer une catégorie d'une vue. Comment faire pour obtenir une vue ayant ces fonctions, si la vue est paramétrée comme "Traiter le contenu de la vue comme du code html" ?

La solution
Il est possible de contourner ce problème, grace aux commandes URL Domino. L'appel d'une vue se fait sous la syntaxe suivante :

http://ServeurDomino/BaseLotusNotes.nsf/NomDeLaVue?OpenView

Ou, éventuellement, l'appel peut se faire sur un masque contenant la vue (vue intégrée) :

http://ServeurDomino/BaseLotusNotes.nsf/NomDuMasqueContenantLaVue?OpenForm

La commandes ?OpenForm et ?OpenView acceptent des paramétres facultatifs qui permettent de jouer sur ce qui doit être affiché par la vue :

CollapseView : Condense toutes les catégories
ExpandView : Déploie toutes les catégories
Collapse=<num> : Condense la catégorie identifiée par son numéro <num> dans la vue
Expand=<num> : Déploie la catégorie identifiée par son numéro <num> dans la vue
Start=<num> : N'affiche que les lignes se trouvant sous la ligne <num> incluse
Count=<num> : Nombre de lignes à afficher

<num> pouvant être hiérarchisé, c'est à dire prendre des valeurs comme 2.3.1 ou 1.5.

Ainsi, la commande URL http://ServeurDomino/BaseLotusNotes.nsf/NomDuMasque?OpenForm&Expand=1.5 aura pour effet d'ouvrir la vue et de déployer la cinquieme sous-catégorie de la premiere catégorie.

Si on dispose des données suivantes :

Boissons
  Froides
    Limonade
    Soda
  Chaudes
    Café
Plats
  Froids
    Sandwich jambon
  Chauds
    Steack frites
    Tartiflette

La commande URL http://ServeurDomino/BaseLotusNotes.nsf/NomDuMasque?OpenForm&Expand=2.1 ouvrira la vue et déploiera la section "Froids" de la section "Plats".
La commande URL http://ServeurDomino/BaseLotusNotes.nsf/NomDuMasque?OpenForm&Expand=2 ouvrira la vue et déploiera la section "Plats", sans déployer ses sous-catégories.

Dans le design de la vue, il suffit donc d'utiliser le code HTML suivant pour toutes les colonnes catégorisées :

<a href='NomDuMasqueContenantLaVue?Openform&Expand=" + @DocNumber + "'>" + TypeAliment + "</a><br>"


Le code HTML généré par cette vue sera :

<a href='NomDuMasqueContenantLaVue?Openform&Expand=1'>Boissons</a><br>
<a href='NomDuMasqueContenantLaVue?Openform&Expand=1.1'>Froides</a><br>
...


Le résultat : une vue avec catégories, mais que l'on peut personnaliser intégralement car elle est 100% html !

Sympa, non ?

Le 14/12/2005 - Benoit Colin


This page is powered by Blogger. Isn't yours?