Forse non molto conosciuti dal grande pubblico, i prodotti Lotus Notes e Lotus Domino sono in campo aziendale fra i più diffusi e apprezzati prodotti di workgroup: grazie all'esperienza maturata dalla casa produttrice in anni di lavoro nel settore della condivisione delle risorse e gestione della sicurezza, sono infatti utilizzati da un numero sempre maggiore di aziende per la gestione del lavoro quotidiano e per lo scambio e condivisione di informazioni.
Lotus Domino è un server al quale i vari client (Lotus Notes) si interfacciano per lo svolgimento di tutta una serie di funzionalità: dallo scambio di documenti alla condivisione di rubriche comuni; dalla gestione della posta elettronica al controllo e sincronizzazione di database distribuiti. Infine, anche nel settore della produzione di web interattivo (in questo caso il client può essere qualsiasi browser, fra cui anche Notes) offrono interessanti funzionalità.
Tutto il sistema, sia il client che il server, è stato progettato per offrire la massima personalizzabilità e programmabilità, grazie al supporto offerto da LotusScript e, di recente, utilizzando un linguaggio di programmazione a oggetti vero e proprio come Java.
In questo articolo vedremo come sia possibile creare programmi che si interfaccino con Notes/Domino sia per la personalizzazione delle funzioni, sia per il collegamento con il mondo esterno. Per un corretto funzionamento delle tecniche che vedremo e degli esempi allegati, si faccia riferimento alla versione 4.6 di Domino.
Non entreremo nel dettaglio del funzionamento di Domino e di Notes, trattazione che esula dagli scopi di questo articolo, rimandando per maggiori approfondimenti alla bibliografia e ai vari articoli pubblicati su questa rivista e sulle altre di Infomedia.
Cosa è Domino
Si è detto che Domino è un server dedicato alla condivisione di risorse: la principale peculiarità e punto di forza del prodotto è l'utilizzo del formato database per la raccolta di ogni genere di dati.
Tutto può essere inglobato in un database di tipo NSF: documenti multimediali, applicazioni, ma anche semplicemente mail, messaggi, file di testo o altro. Tutto quello che si desidera inserire nel sistema di gestione condiviso viene gestito tramite database. Anche i file di configurazione del sistema, quelli di impostazione dei profili utente e gli archivi di posta sono database. Con i debiti adattamenti, questo tipo di concezione la ritroviamo in (o deriva da) Unix, dove tutte le risorse di sistema vengono viste come file.
Ogni database, inoltre, è personalizzabile per mezzo di LotusScript o Java in modo da creare delle vere e proprie applicazioni. Questa caratteristica, che all'inizio porta un po' di confusione nell'utente/programmatore alle prime armi, ha il grosso vantaggio di uniformare la metodologia di gestione delle varie risorse.
Tenendo presente che, in maniera quasi automatica, un database può essere pubblicato su Internet senza sforzi aggiuntivi, si comprende la potenza del sistema: un archivio di prodotti, ad esempio, può essere trasformato in pagine HTML (è il server stesso che se ne preoccupa in maniera dinamica), con la possibilità di eseguire ricerche e aggiornamenti in tempo reale oppure sincronizzazione con altri database. Modificato il database con il client Notes, la parte web delle pagine HTML resta sempre aggiornata.
La pubblicazione dinamica sul web è un meccanismo molto simile a quello che da poco è stato introdotto con le pagine ASP o, ancora più recentemente, con JSP: in questo caso, però, la parte di interfacciamento web si integra con un back-end aziendale altamente sofisticato, con un livello di sicurezza molto elevato.
Possiamo dunque affermare, in maniera forse un po' sintetica ma sicuramente efficace, che in Domino tutto è un database e tutte le operazioni di gestione possono essere eseguite semplicemente modificando tali oggetti: per quello che vedremo in seguito, questo punto è molto importante.
Prima di procedere occorre fare una precisazione sulla natura del dualismo Notes/Domino: il primo è il client e può essere utilizzato anche in modalità standalone, senza appoggiarsi a un server Domino, per gestire i database NSF o leggere la posta collegandosi con un server POP3 o SMTP. Domino, invece, è un server che offre una serie di servizi orientati alla gestione del lavoro di gruppo: gestione della posta elettronica, sincronizzazione dei database fra i vari client, server HTTP, oltre ad altre funzionalità avanzate.
È possibile scrivere programmi che si interfaccino con i vari database NSF e che su tali archivi eseguano certe operazioni. A volte questo significa l'interazione con il client, ad esempio se vogliamo scrivere un agente, a volte con il server, nel caso dei servlet o di applicazioni esterne che debbano manipolare un determinato database. Molto brevemente possiamo dire che, dal punto di vista del motore di gestione dei dati e dei vari servizi, i due prodotti sono praticamente integrati l'uno nell'altro e che, per gli scopi del nostro articolo, possono essere pensati come una cosa sola.
L'interfacciamento con il mondo esterno
Esistono varie tipologie di programmi Java per la gestione e l'interazione con Domino/Notes. La prima distinzione è legata all'ambiente di esecuzione dell'applicazione stessa: possiamo infatti avere applicazioni esterne che, per mezzo di una particolare interfaccia, si colleghino con Domino, oppure applicazioni che risiedano dentro il sistema e che vengano eseguite dal sistema stesso.
In entrambi i casi si devono utilizzare le Java Notes Object Interface (NOI) API, un set di classi Java create da Lotus proprio per tale scopo. La strada più semplice per "entrare" in Domino dall'esterno è creare un'applicazione Java che utilizzi tali package: in tal modo è possibile aprire i vari database ed effettuare le classiche operazioni di lettura, scrittura e modifica. Per quello che si è detto poco sopra, questo tipo di operazione può significare sia la gestione di dati, sia la gestione del sistema stesso.
Un'applicazione interna, invece, si distingue per il fatto che viene eseguita dal sistema, dato che, utilizzando Java, l'agente viene gestito dalla JVM del server. Anche in questo caso abbiamo due tipologie di programmi: gli agenti, che agiscono direttamente nell'ambito di un database e qui spendono il loro ciclo di vita, oppure i servlet.
Un servlet Domino è a tutti gli effetti un servlet standard derivante dalla HttpServlet del JDK 1.2 ed è in esecuzione all'interno della JVM del web server di Domino. La differenza fondamentale fra un servlet e un agente è che quest'ultimo è qualcosa che non può essere pensato al di fuori del database sul quale viene fatto lavorare: ad esempio possiamo pensare a un agente che esegua, a intervalli regolari o su comando, operazioni di pulizia e riordino del database stesso.
Un servlet, invece, viene eseguito tutte le volte che se ne richiede l'esecuzione, secondo il classico schema init() più doGet()/doPost(). Tipicamente viene utilizzato per estendere le funzionalità del web server andando a prelevare informazioni nei vari file NSF, i database di Domino.
Perché Java
Anche se ormai Java ha assunto una popolarità enorme, verrebbe da chiedersi come mai prodotti come Domino e Notes si appoggino così fortemente a Java per la gestione e la comunicazione verso l'esterno. La risposta viene direttamente dall'analisi delle principali caratteristiche del linguaggio.
La portabilità di Java si sposa perfettamente con la politica di IBM, la casa madre di Lotus, che fa della copertura globale delle varie piattaforme uno dei suoi punti di forza. Dato che sono disponibili versioni del prodotto per i più importanti sistemi operativi sul mercato, è possibile sia portare i database da una piattaforma a un'altra, sia, grazie alla portabilità di Java, portare i programmi: agenti, applicazioni e servlet.
La sicurezza che Java offre diviene quasi indispensabile se si pensa a come IBM si sia impegnata in tal senso. La facilità con cui in Java è possibile interfacciarsi con il mondo delle reti risulta essere un ulteriore punto a favore per l'impiego in un prodotto fortemente orientato al lavoro di gruppo basato sulla rete. Il fatto, infine, che Java sia un linguaggio conosciuto da molti permette una facile integrazione di coloro che inizialmente possono avere una ridotta conoscenza del sistema, ma hanno una buona familiarità con Java.
Sebbene Java rappresenti la strada più semplice per la programmazione in Domino, esiste l'alternativa di LotusScript, che però offre poche possibilità in confronto a Java, oltre alla possibilità di interfacciarsi tramite CORBA a un mondo composto da un numero praticamente infinito di opzioni e possibili alternative. Java è solo una delle strade possibili, forse la più semplice e immediata, ma non l'unica.
Installazione
Indipendentemente dal tipo di programma che si desidera realizzare — agente, applicazione o servlet — per poter accedere ai database di Notes è necessario installare le classi contenute nel package NOI.
Come al solito non si tratta di un'operazione complessa: è sufficiente copiare in una directory del file system il file Notes.jar, che contiene tutte le classi del package lotus.notes, e modificare il classpath in modo che la JVM possa trovare tale file. È anche necessario aggiungere al path di sistema la directory dove sono presenti tutti i vari programmi server e client, tipicamente collocati in xxx\xxx\notes.
Fatte queste poche operazioni, si può passare alla realizzazione vera e propria dei programmi. Vediamo quindi che cosa sia necessario fare per creare una delle tre tipologie di programmi: applicazioni esterne, agenti e servlet.
Applicazioni
La prima cosa di cui tener conto è che una qualsiasi applicazione deve estendere la classe NotesThread, contenuta nel package lotus.notes, che estende a sua volta la Thread del JDK. Questo passaggio è necessario per poter utilizzare la particolare gestione multithread presente in Notes/Domino.
Dal punto di vista implementativo si possono seguire due strade: specializzare la classe NotesThread (vedi l'esempio primaApplicazioneThread.java) oppure implementare l'interfaccia Runnable (primaApplicazioneRunnable.java). Nel primo caso l'esecuzione del programma avviene per mezzo del metodo NotesThread.runNotes, che viene invocato automaticamente all'invocazione del metodo start(), così come Thread.start() invoca Thread.run().
Nel secondo caso, invece, all'interno del main viene creato un NotesThread e mandato in esecuzione. In questo caso si dice che la classe Thread standard viene utilizzata come entry point per l'esecuzione del codice. Non ci sono ulteriori particolarità di cui tener conto.
Agenti
Un agente è un particolare programma che "vive" dentro un database NSF: può eseguire operazioni sul database automaticamente, a intervalli prestabiliti, o su comando. Per realizzare un agente Notes in Java la cosa più importante da tener presente è la derivazione dalla classe AgentBase.
AgentBase esegue alcune importanti operazioni, come le inizializzazioni di basso livello del motore di gestione dati o la creazione di una sessione, indispensabile per l'esecuzione dell'agente stesso. Si occupa anche di certi servizi minori, come la creazione di un timerThread: l'obiettivo è controllare che l'agente non prenda il sopravvento sul sistema e, in tal caso, procedere a uccidere l'agente stesso; il termine tecnico, piuttosto pittoresco, è "terminated with extreme prejudice".
Tutto il codice che dovrà essere eseguito dall'agente deve essere inserito nel metodo NotesMain, punto di inizio dell'agente stesso. Questo passo è fondamentale: AgentBase estende infatti NotesThread, che deve essere eseguito secondo la sua procedura personale, in modo che, tra le altre cose, venga utilizzato il metodo runNotes.
Dato che ci deve essere l'assoluta certezza che il metodo AgentBase.runNotes() sia invocato dalla classe NotesThread, e non dalla classe in costruzione, esso è dichiarato final. Nell'esempio primoAgente.java si può vedere nel dettaglio come realizzare l'agente: si noti che non viene specificato il nome del database, essendo quello in cui l'agente stesso viene eseguito e ricavato con il metodo AgentContext.
Servlet
Infine, la parte più semplice: non ci sono particolari accorgimenti da tenere presenti nella produzione di un servlet. In questo caso il servlet viene visto come un'applicazione esterna al motore di gestione dei database; non vi è nessun riferimento a NotesThread, essendo di fatto i servlet dotati di thread e quindi tale gestione avviene in maniera del tutto trasparente.
Come si può osservare dall'esempio del file primoNotesServlet.java, il processo è molto semplice e praticamente si segue la normale procedura utilizzata per la realizzazione di un servlet standard. La procedura per attivare il supporto per i servlet e installarne uno specifico è un po' particolare e per questo si veda il riquadro "I servlet in Domino".
Manipolazione di dati
Dopo aver visto i concetti di base che, seppur in forma molto sintetica, dovrebbero essere sufficienti per muovere i primi passi, resta da vedere come aprire un database e leggere o scrivere i dati al suo interno. Moltissime sarebbero le cose da dire, soprattutto relativamente alla natura e strutturazione di un database Notes: non essendoci lo spazio per entrare nel dettaglio di questi aspetti, rimandiamo alla bibliografia in fondo all'articolo.
Molto sinteticamente, l'elemento base in un database NSF è il documento, che potrebbe essere assimilabile al concetto di record di un database relazionale (d'ora in poi RDB). Ogni documento è composto da item, le colonne in un RDB. Tutto l'insieme dei documenti viene collezionato in un form, equivalente a una tabella in RDB, e su ogni form è possibile creare delle viste, equivalenti ai recordset in RDB, la cui funzione è quella di dare una visione particolare: un sottoinsieme di documenti o merge particolari.
È sicuramente una semplificazione un po' troppo rigida, dato che la potenza di un database NSF sta proprio nella flessibilità, ma per mancanza di spazio e necessità di sintesi possiamo assumere che sia sufficientemente corretta. Le classi contenute nel package lotus.notes permettono la manipolazione di tutti gli elementi tipici di un file NSF: database, utenti, form, documenti, collezioni di documenti, viste e item.
Ad esempio, se si desidera aprire un database possiamo utilizzare le seguenti istruzioni:
try {
NotesThread.sinitThread();
lotus.notes.Session s = Session.newInstance();
lotus.notes.Database db = s.getDatabase(null, "ArticoliJava");
} catch (NotesException nte) {
}
Dopo aver creato una sessione, operazione necessaria in Notes e che equivale a una specie di login, possiamo ottenere il database per mezzo del metodo Session.getDataBase(). Per fare riferimento al database basta indicarne il nome, senza estensione perché sono tutti NSF, e non importa specificare la sua collocazione: secondo la convenzione, non obbligatoria, tipica di Notes, tutti i database sono collocati nella stessa directory di sistema e questo semplifica notevolmente le cose.
Si pensi, ad esempio, se si decidesse di portare la propria applicazione dalla piattaforma Windows NT a Unix, alla fatica risparmiata per non dover gestire le differenti convenzioni nei path per mezzo di File.pathSeparatorChar.
Una volta ottenuto il database possiamo eseguire alcune semplici operazioni per ricavarne i valori. Ad esempio potremmo per prima cosa ottenere il nome delle colonne di una certa vista:
lotus.View NotesView;
NotesView = NotesDb.getView("Pubblicati");
Vector NotesViewColumns = NotesView.getColumns();
Nel vettore NotesViewColumns sono ora contenute le varie colonne della vista Pubblicati. Possiamo eseguire una ricerca con il metodo FTSearch: questo esegue una ricerca testuale e di fatto modifica la vista, lasciandovi solo i documenti che soddisfano la ricerca, una specie di screening.
NotesView.FTSearch("FIELD Autore contains Puliti");
Document doc = NotesView.getFirstDocument();
Con un semplice ciclo è quindi possibile ottenere il valore di tutti i documenti rimasti nella lista:
while (doc != null) {
String title = doc.getItemValueString("titolo");
doc = NotesView.getNextDocument(doc);
}
Come al solito, tutte queste operazioni devono essere inserite in blocchi di protezione try-catch. Il metodo FTSearch, per quanto comodo, è però piuttosto lento. In alternativa si può utilizzare il più veloce lotus.notes.View.getAllDocumentsByKey, come ad esempio:
DocumentCollection dc = NotesView.getAllDocumentsByKey(key, false);
L'oggetto DocumentCollection restituito rappresenta una collezione di documenti non associati a nessuna vista e per questo non gestibili per mezzo di una View. Se invece si desidera inserire dei dati nel database, possiamo scrivere:
lotus.notes.Document d = NotesDb.createDocument();
d.appendItemValue("titolo", title);
d.appendItemValue("autore", auth);
boolean ret = d.computeWithForm(true, true);
d.save();
La prima riga serve per creare un documento nuovo e vuoto. Successivamente si inseriscono uno a uno i vari item, le colonne del RDB. Infine è molto importante l'esecuzione di Document.computeWithForm(): serve per processare il nuovo documento con il form in questione, quello attivo in quel momento nel database. Questo passaggio serve anche per eseguire determinati filtri o istruzioni associati al form.
Se il processamento è valido, il nuovo documento viene definitivamente inserito al suo posto, nel form; altrimenti resta sciolto e non associato a nessun form.
Conclusione
Concludiamo questa breve panoramica introduttiva alla programmazione Java di Domino 4.6. Le cose da dire sarebbero ancora veramente molte, ma spero che quel poco che abbiamo visto in questo articolo sia sufficiente per avere un'idea delle possibilità offerte e per iniziare a fare un po' di prove.
Come si è potuto notare, le operazioni in alcuni casi sono un po' macchinose e sicuramente meno agili e sintetiche delle equivalenti del linguaggio SQL che si usano in genere per mezzo di JDBC su un database relazionale. È bene notare, però, un aspetto molto importante: pur non essendo la struttura di un database di Notes a oggetti, la sua organizzazione particolare si sposa piuttosto bene con tale filosofia di programmazione. Per questo, dopo un po' di fatica iniziale, si potrà notare come in realtà il modello organizzativo sia molto vicino a Java, quasi fosse stato pensato per questo linguaggio.
Sicuramente mi sento di consigliare a tutti coloro che utilizzano Notes/Domino da tempo di iniziare a fare delle prove con le NOI per Java, ma anche a chi conosce bene Java di avvicinarsi a Domino per la porta di servizio, iniziando a fare delle prove di programmazione.
Per maggiori approfondimenti sui temi visti rimando alla lettura del forse unico testo disponibile attualmente [DomProg]. Per quanto riguarda invece la gestione di Notes e dei database, esistono molte pubblicazioni in merito, una delle quali potrebbe essere [MastNotes]. Per quanto riguarda gli approfondimenti relativi ai servlet, esiste una bibliografia praticamente sterminata: mi limito a suggerire le varie pubblicazioni apparse su MokaByte [ServletIntro], [ServletWeb], [SerlvetStato].
Bibliografia
- -
- [DomProg] *Programming Domino 4.6 with Java*, Bob Balaban, IDG, ISBN 1-5585-1583-6.
- -
- [MastNotes] *Mastering Lotus Notes*, 3rd edition, K. Brown, F. Koutchouk, S. Habernan, Sybex.
- -
- [ServletIntro] "Java Servlet", Fabrizio Giudici, MokaByte 11, settembre 1998.
- -
- [ServletWeb] "Servlet, JDBC e JavaServer: quando l'unione fa la forza (e semplifica la vita)", Giovanni Puliti, MokaByte 20, giugno 1998.
- -
- [SerlvetStato] "Gestire le sessioni con le servlet", Gerardo Poggiali, MokaByte 26, gennaio 1999.
- -
- [JDK12] "Speciale JDK 1.2", Dev 55, settembre 1998.
