MokaByte Numero  44  - Settembre 2000
Lotus Domino e Java
Le form 
III parte
di 
Matteo Baccan
Viaggio nel mondo di Lotus Notes e 
dell'interfacciamento con Java

Lotus Domino è sicuramente uno degli strumenti migliori per la raccolta di documenti aziendali di tipo eterogeneo. Vediamo ora com’è possibile utilizzare Internet come fonte di acquisizione dati, analizzando il funzionamento delle form di Lotus Domino, quando vengono utilizzate all’interno di un browser

Come abbiamo visto nella prima puntata di questo corso, costruire una maschera di inserimento dati, utilizzabile in ambito Internet è un’operazione molto semplice. Poter poi mischiare del design Notes con del codice HTML, è una possibilità molto interessante e permette di superare quelli che sono gli eventuali vincoli che, l’ambiente di disegno, ci andrebbe a porre durante le fasi di preparazione delle singole maschere.
Il primo aspetto che analizzeremo ora è dato dal modo con il quale, all’interno di Notes, è possibile inserire delle classi Java, che verranno eseguire all’ingresso e all’uscita della form.
 
 
 
 

Campi speciali ed eventi
Per poter effettuare questo tipo di operazione, esistono vari modi. Il primo in assoluto, pensato dai progettisti Notes, è quello di utilizzare un particolare tipo di campo, nel quale inserire il nome dell’agente che deve essere eseguito in partenza o in uscita dalla form.
Tale campo è $$QueryOpenAgent per l’agente d’ingresso nella form e $$QuerySaveAgent per l’agente d’uscita dalla form.
Dopo aver definito l’uno o l’altro campo, in base alle esigenze della propria applicazione, occorre mettere, nel valore di default di tale campo il nome dell’agente che verrà richiamato in automatico da Notes. Ad esempio

"testQueryOpenAgent"

e naturalmente, fra la lista degli agenti disponibili, ne andrà creato uno con pari nome.
Fate attenzione però al fatto che l’agente sia realmente disponibile, infatti nel caso in cui non lo fosse Notes non sarebbe in grado di comporre la maschera e di renderla disponibile lato browser, generando un errore di form non disponibile lato web browser e Invalid Document Identifier a livello di console di Notes. 
 
 
 

Figura 1 - Messaggio  di errore nella esecuzione di un 
agente visualizzato nella finestra del server

 
 
 
Figura 2 -  Messaggio  di errore nella esecuzione di un 
agente visualizzato nella finestra del browser

 

Questo modo di scrivere un agente, da mandare in esecuzione prima della visualizzazione della form o al suo salvataggio, è sicuramente stato uno stratagemma inventato nei tempi in cui si iniziava ad utilizzare Notes in ambito Internet. Ne è prova il fatto che, all’interno dei manuali delle ultime versioni, non si fa menzione di tale campo, fra la lista dei campi speciali.
Tale tecnica è stata sostituita, dalla versione 4.6.x, ma in modo più marcato dalla 5.x, con l’utilizzo di due eventi presenti all’interno della lista degli eventi del form. Tali eventi sono: WebQueryOpen  e WebQuerySave.
Se provate a posizionare Domino Designer su tali eventi, noterete che Notes proporrà di default due @command:

@Command([ToolsRunMacro]; "<...>")

In tali @command andranno inseriti il nome degli agenti da eseguire, quindi, nel nostro caso:

@Command([ToolsRunMacro]; "testQueryOpenAgent")

Nel database d’esempio allegato al corso, troverete due form, con al loro interno le due diverse implementazioni di OpenAgent e SaveAgent.
Vediamo ora come devono essere scritti gli agenti, all’interno di Lotus Notes.
 
 
 

Figura 3 - Caratteristiche dell’agente

 
 

Che tipo di agenti possiamo scrivere
Notes ci permette diverse modalità di scrittura, che si sono evolute col passare del tempo.

  • Formula. Rappresenta una semplice formula, come potrebbe essere l’apertura di una nuova form. Nel nostro caso però tale tipo di agente risulta alquanto difficile da utilizzare.
  • Simple action(s). Rappresenta un’operazione più complessa, come ad esempio l’inoltro di una mail o l’esecuzione di un altro agente.
  • LotusScript. Questa è la modalità classica di scrittura di un agente, prima dell’avvento di Java, cioè fino alla versione 4.5.x. Essendo però le classi Java di Notes derivate direttamente dalla classi di LotusScript è ragionevole affermare che tutto quello che possiamo fare in LotusScript, possiamo rifarlo ora con un gente Java.
  • Imported Java. È la prima modalità di utilizzo di un agente Java in Notes. Consiste nella scrittura, con un qualsiasi programma, dell’agente all’esterno di Notes e nell’importazione del relativo .class file all’interno del database. Questo modo di scrivere gli agenti previene, almeno in prima istanza, la possibilità da parte di un altro programmatore di riutilizzare il codice che è stato utilizzato per il proprio lavoro, dato che non vi è traccia del sorgente all’interno del database.
  • Java. Dalla versione 5.x di Notes è possibile scrivere, direttamente all’interno del database, l’agente in linguaggio Java. Sarà poi Notes a compilare il sorgente e a renderlo disponibile all’applicazione. In questo modo il database diventa autosufficiente e non occorre, come nel caso dell’Imported Java, ricordarsi di fare un backup dei sorgenti dell’applicazione, oltre che del file .nsf stesso.
Al fine di comprendere meglio come poter scrivere del codice Java, che interfaccia una form, utilizzerò la possibilità di scrivere internamente all’agente il relativo codice Java. 
Per chi non disponesse di una versione 5.x di Notes, sarà comunque possibile scrivere un agente esterno a Notes stesso, compilarlo, avendo cura di includere nel CLASSPATH il file Notes.jar, presente all’interno della directory di Notes, ed importarlo come Imported Java. Per il resto lo sviluppo rimane identico, occorre infatti derivare dalle stesse classi e scrivere lo stesso codice.
 
 
 
Figura 4 - Configurazione server

 

Scriviamo il primo agente Java
Il primo particolare importante da sapere, quando si scrive un agente Java, è da quale classe si deve necessariamente derivare. Tale classe è: AgentBase. 
Se provate ad estrarre e a decompilare le classi Notes, contenute nel file Notes.jar, noterete che la classe AgentBase è derivata direttamente da Thread. Notes si limita semplicemente ad implementare dei metodi aggiuntivi che andrà poi a gestire l’Agent Manager, prima di eseguire l’agente vero e proprio.
 

Un altro particolare interessante è dato dal fatto che, ogni agente è inserito all’interno di una propria area di memoria e non può, per dei vincoli di sicurezza, dialogare con altri agenti. Questo tipo di architettura è stata pensata per evitare che agenti “maliziosi” potessero interagire con altri compromettendone l’esecuzione.
Una volta effettuata la derivazione da AgentBase occorre poi implementare il metodo
 

public void NotesMain()

sarà poi cura dell’Agent Manager richiamare tale metodo al momento giusto e con i giusti oggetti pronti per poter essere interrogati ed utilizzati.
Un altro particolare importante da sapere, prima di partire, è che, lo stream di output System.out in realtà punta alla console di Notes. Quindi un comando come:

System.out.println("OpenAgent");

non farà altro che produrre una riga all’interno del log di Notes. Attenzione però a non abusare di questo comando in quanto, la scrittura all’interno del log, rallenta abbastanza l’esecuzione dell’agente stesso, e si può rivelare una grave perdita di performance.
Vediamo a questo punto un piccolo esempio che sfrutta tutti i punti descritti finora:

import lotus.domino.*;
public class JavaAgent extends AgentBase {

 public void NotesMain() {
  System.out.println("OpenAgent");
 }

}

Come si può notare è stata inserita la direttiva import delle classi lotus.domino.* per fare in modo che il compilatore Java potesse, in modo corretto, ereditare dalle classi Notes l’agente corrente.
Il nome della classe è comunque implementabile a discrezione del programmatore. JavaAgent è semplicemente un default che Notes propone e che può essere sostituito in qualsiasi momento.
 
 
 

Figura 5 - Abilitazione utente

 

È inoltre interessante notare che, nel caso che la classe sia implementata interamente in Notes, non occorre fare delle modifiche all’environment, come il ritocco del CLASSPATH, in quanto la corretta impostazione viene fatta direttamente da Notes, al momento della compilazione della classe.
Vediamo ora come possiamo iniziare a leggere e scrivere dei valori, prima che la form venga visualizzata. 
 
 
 

Valori di default
La prima operazione che faremo ora sarà quella di dare un default ad un campo.
Per poter effettuare tale operazione ci serve accedere al documento corrente, cioè a quel documento che Notes sta preparando per mandare poi al browser, che ne gestirà l’inserimento dati.
Per arrivare a tale documento occorre, prima di tutto, accedere alla sessione correntemente attiva all’interno di Notes, tramite il metodo getSession() che troviamo implementato all’interno della classe base del nostro agente. Dalla sessione occorre poi accedere all’oggetto AgentContext che gestisce l’agente correntemente in esecuzione e da tale oggetto possiamo poi accedere al Document corrente, tramite il metodo getDocumentContext() della classe AgentContext.
Una volta che si è raggiunto il documento corrente è poi molto semplice manipolarlo per poter fare delle personalizzazioni.
Se volessimo, ad esempio, dare un valore di default ad un campo, contenuto all’interno di una form, della quale l’agente corrente è il WebOpenAgent, non dovremo fare altro che scrivere le seguenti righe:

try {
   Session session = getSession();
   AgentContext agentContext = session.getAgentContext();
   Document doc = agentContext.getDocumentContext();

   // Assegno il valore di default al campo cNome
   doc.replaceItemValue("cNome","prova");

} catch(Exception e) {
   e.printStackTrace();
}

Le prime tre righe sono ovvie, in quanto implementano il concetto appena spiegato, la parte interessante è data dalla riga successiva, che assegna al campo cNome il valore “Prova” in maniera statica, gestendo così un default su campo.
In realtà questo meccanismo è importante per capire come è semplice accedere ai campi di una form prima che vengano visualizzati. 
Potevamo infatti leggere tali valori da una connessione JDBC, ed utilizzare la form come maschera di modifica dati di un record di database.
Vediamo ora com’è possibile gestire, con questa tecnica una visualizzazione condizionale dei valori di una form.
 
 
 

Figura 6 - Esecuzione corretta degli agenti

 

Visualizzazione condizionale
Le form Notes hanno la caratteristica di poter avere delle parti condizionabili, in base al valore di un campo, o di un’espressione. Sfruttiamo a nostro vantaggio questa caratteristica, inserendo un nuovo campo, all’interno della form, e chiamandolo abilita.
Aggiungiamo ora due nuovi campi, su due righe differenti, e poniamo il primo campo non visualizzato se abilita contiene il valore “S” ed il secondo non visualizzato se il valore di abilita contiene il valore “N”.
A questo punto, sempre dalle proprietà del campo abilita, evitiamo che il campo venga visualizzato lato web, selezionando l’opzione Hide paragraph from Web browsers.
A questo punto, all’interno dell’agente proviamo ad aggiungere la seguente riga:

doc.replaceItemValue("abilita","S"); 

In questo modo forziamo un valore di default a “S” per il campo abilita. Ne consegue che, il browser, visualizzerà solamente il secondo campo, nascondendo il primo, in quanto il motore di composizione della form, dopo aver eseguito il nostro agente, ha constatato la non visualizzabilità della prima riga.
Questo esempio, ci permette di capire come, tramite un semplice WebOpenAgent, sia possibile dare dei default e condizionare la visualizzazione di una form.
In questo caso abbiamo limitato la visualizzazione ad una sola riga, se però al posto della riga ci fosse stato un intero subform o più righe, l’effetto non sarebbe cambiato.
 
 
 

Figura 7 - Valore di default

 
 

Autorizzazioni
Ultimo particolare sul quale soffermarci, ma non il meno importante, è dato dal tipo di autorizzazioni che si debbono avere, lato server, per poter scrivere questo tipo di agenti.
Non basta infatti crearli ed associarli ad una form, occorre anche autorizzare, all’interno dell’ambiente di configurazione di Notes, l’utente che ha salvato l’agente all’esecuzione degli agenti.
Per poter fare questo occorre accedere alla parte di security del server e porre, il nome dell’autore dell’agente, informazione che troviamo fra le proprietà dell’agente stesso, nella lista di nomi che possono eseguire agenti di tipo restricted.
Ci possiamo accorgere del fatto che questa modifica debba essere fatta, quando il browser restituisce l’errore 500 al momento dell’esecuzione di una form, il cui WebOpenAgent sia stato salvato da un utente non abilitato.
 

Figura 8 - Visualizzazione condizionale

 
 
 

Conclusioni
In questa seconda puntata è stato spiegato il modo con il quale è possibile interagire con delle form Notes, al momento della loro creazione, tramite un semplice agente. Nella prossima puntata vedremo anche degli esempi di gestione del salvataggio dei dati tramite un WebSaveAgent e del modo col quale è possibile evitare il salvataggio, in concomitanza di particolari condizioni.

Il database di esempio citato nell'articolo può essere scaricato qui
 
 
 
 

Bibliografia
[1] http://www.lotus.com sito Internet di riferimento per i prodotti Lotus
[2] http://www.notes.net sito ufficiale di Lotus Domino. Da questo sito è possibile scaricare tutti gli aggiornamenti di Domino, dalla versione 4.0 all’ultimissima versione disponibile.
[3] http://www.infomedia.it/artic/Baccan, sito contenente alcuni articoli di approfondimento degli argomenti trattati.
 

Matteo Baccan è uno specialista di progettazione e sviluppo in C++, Java e Lotus Notes, nonché coautore di dBsee 4, dBsee++ ed autore di dBsee400. Attualmente si occupa dello studio di tecniche avanzate di programmazione in ambito Internet/Intranet tramite Lotus Notes e Java, presso ISA Italian Software Agency. Si possono consultare alcune sue pubblicazioni presso http://www.infomedia.it/artic/Baccan. Può essere contattato tramite e-mail all'indirizzo baccan@infomedia.it

Chi volesse mettersi in contatto con la redazione può farlo scrivendo a mokainfo@mokabyte.it