MokaByte Numero  37  - Gennaio 2000 
 
JDBC e WEB 
I parte
di 
Mauro Molino
Come devo strutturare la mia applicazione se voglio interfacciare una base di dati con il web? In particolare cosa devo fare per permettere ad una applet di leggere i dati contenuti in tale db?


L’implementazione di un applet che legga/scriva da un database remoto è la scusa per una serie di articoli didattici, per ripassare tecniche e librerie standard di Java, con un occhio alla “compatibilità all’indietro”
Introduzione
JDBC è sicuramente uno strumento semplice ed efficace nella gestione delle basi dati in Java ed ormai ci abbiamo fatto l’abitudine. Prima o poi però ci scontriamo con il problema di dover gestire un database da un applet, e qui le cose si fanno un po’ più complesse; infatti JDBC di per sé non è concepito come uno strumento di accesso via Web, o meglio  è vero che esistono dei driver Jdbc in grado di interagire con motori di database remoti ma, “casualmente”, la maggior parte delle volte che ci scontriamo con un’esigenza di questo tipo il database da utilizzare è Acces il quale, non solo non è un motore di database, ma ci costringe addirittura ad utilizzare il celeberrimo bridge JDBC-ODBC. Ci siamo tutti chiesti almeno una volta: ma è possibile che non esistano driver JDBC nativi per Access ? Risposta: non è che in linea di principio sia impossibile scrivere dei driver JDBC per Access ( ammesso che veramente non ne esistano), il punto è che Access incarna il teorema del database standard a modo suo, tant’è vero che molte “meta”–proprietà in genere presenti sulla maggior parte dei database su Access mancano o sono implementate diversamente. Ma bando alle lamentele e cerchiamo invece una soluzione quantomeno plausibile.
 
 
 

Le alternative
Intanto è chiaro che vista la situazione abbiamo comunque bisogno di uno strato intermedio tra la nostra pagina web e il database ( e dagli con il n-tier !!), si tratta ora di decidere quale sia la soluzione più adatta.  Per parlare di ciò che è già pronto possiamo subito dare un’occhiata al Remote Scripting. Si tratta di una tecnologia Microsoft, costituita da un applet Java ( strano ?!) in grado di eseguire delle funzioni scripting lato server, nel nostro caso interrogazioni  a database e restituire dei dati. Il vantaggio principale rispetto ad esempio alla tecnologia ASP è che in ASP le elaborazioni server-side avvengono al momento di creare una pagina, quindi ogni elaborazione richiede il caricamento di una nuova pagina web. In Remote Scripting invece c’e’ uno scambio di dati fra client e server senza bisogno di richiedere al server una nuova pagina html/asp.Le chiamate alle funzioni di Remote Scripting e la manipolazione dei dati di ritorno avvengono via scripting client.E’ un sistema ibrido, che richiede il supporto ASP sul server e non semplicissimo da debuggare soprattutto per funzioni complesse, però piuttosto comodo.
Riportiamoci ad un mondo più “Java puro”; se parliamo di accesso remoto a qualcosa la prima sigla che ci viene in mente è RMI (Remote Method Invocation). E’ l’uovo di Colombo: il client chiama l’esecuzione di metodi sul server, che svolge il lavoro e restituisce i dati. Problema: poche sono le VM integrate nei vari browser in grado di gestire RMI in maniera decorosa, per cui o siamo sicuri della piattaforma client utilizzata, o dobbiamo necessariamente scartare questa ipotesi a priori, anche perché molti sono quelli allergici all’interazione con il rmi registry ( abbiamo tutti subito traumi a causa di qualche registry !!).
Altra ipotesi: connessione pura TCP/IP fra applet e processo server con interscambio di dati. Il processo server interpreta le istruzioni che riceve dal client, interagisce con il database e restituisce i dati al client. A prima vista sembrerebbe piuttosto complesso, però gli strumenti messici a disposizione dal nostro linguaggio preferito ci possono venire in aiuto. Per di più potrebbe essere l’occasione per fare un po’ di ripasso su alcuni fondamenti delle librerie di Java. In questo primo articolo faremo un’analisi approfondita dell’architettura per poi, nei prossimi, lanciarci a capofitto nella scittura del codice.
 
 
 

Analisi preliminare
Cominciamo a vedere la struttura generale del nostro progetto, poi vedremo le varie fasi in dettaglio. Come mostrato in figura 1, abbiamo 3 entità distinte : il nostro applet, un applicativo server e un database. 
 
 

Figura 1

L’applet viene naturalmente  eseguito sul client, mentre l’applicativo server risiede sul web server, e questo obbligatoriamente, in quanto ricordiamo che un applet generico può instaurare connessioni tcp/ip solo con il server dal quale è stato scaricato. Per quanto riguarda il database, per  semplicità consideriamo il caso in cui anch’esso si trovi sulla stessa macchina del web server, in modo da poter utilizzare semplicemente il bridge Jdbc-Odbc ( stiamo ipotizzando un database Access).
Il percorso (1) della figura rappresenta il canale attraverso il quale l’applet comunica all’applicativo server ciò che vuole. A questo fine stabiliremo dei formalismi comunicativi, in modo che sia possibile per l’applicativo server riconoscere se i dati inviati dall’applet siano istruzioni o query sql. Una volta effettuato il parsing del ricevuto, l’applicativo server si interfaccerà con il database (percorso (2) ) via JDBC, ottenendo (3)  i dati di ritorno. Su questi dati eseguirà le sue elaborazioni per creare uno streaming di dati che attraverso (4) invierà all’applet il quale, infine, ne estrarrà ciò che gli serve per eventualmente visualizzarli. 
Concettualmente i vari passaggi sono abbastanza semplici, ma la loro implementazione richiede l’utilizzo di tutta una serie di concetti e librerie Java, e questo rappresenta forse il vero valore didattico di questo e dei prossimi articoli della serie.
 
 
 

In dettaglio
A questo punto focalizziamoci sulle singole fasi del processo, in modo da individuare il più precisamente possibile i blocchi funzionali della nostra architettura. Partiamo dall’applet: in figura 2 vediamo i blocchi funzionali costitutivi, che ci permettono subito di “atomizzare” il più possibile la fase di sviluppo.
 
 

Figura 2

Abbiamo diviso l’applet in quattro “moduli”. Tralasciamo per il momento l’interfaccia utente, dato che dei quattro è sicuramente la più banale, o comunque quella che richiede meno spiegazioni. Il modulo che abbiamo chiamato “creazione query”, è quello che si occupa di creare una stringa, da inviare all’applicativo server, che contenga sia istruzioni che dati. Facciamo un esempio: supponiamo che si voglia ordinare all’applicativo server di eseguire la query “select * from clienti” sul database “prova” ( prova sarà il nome ODBC del file access). Possiamo pensare di strutturare la stringa di richiesta in un modo simile a questo: “ Database: prova ; Query: select * from clienti ;” , dove “Database” e “Query” saranno riconosciute dall’applicativo server come parole chiave, e ciò che sta fra i due punti e il punto e virgola come dato riferito alla parola chiave( quindi punto e virgola e due punti saranno riconosciuti come separatori). Con lo stesso metodo è possibile creare ulteriori parole chiave che possano essere utili, ad esempio per comunicare il massimo numero di record da restituire o qualsiasi altra “direttiva” che istruisca l’applicativo server su cosa e come fare qualcosa.
Il modulo di gestione dei socket si occuperà essenzialmente di creare i socket di input/output e di instradare /ricevere i dati. Il blocco forse più complesso è quello che si occuperà del parsing dei dati. Il metodo di funzionamento è speculare rispetto a quello del modulo di creazione della query; infatti, ricevuto uno streaming di dati, il modulo cercherà delle parole chiave e i dati ad esse associate. 
Facciamo anche in questo caso un esempio; supponiamo di ricevere una stringa di ritorno di questo tipo: “Fields: Nome, Cognome, Indirizzo ; Values: Franco,Bassi,via Po 12 && Mario,Vecchi,via Tevere 8 && Giulio,Antani,via Arno 1 ; ". Il metodo è lo stesso visto prima, “Fields” e “Values” sono parole chiave, due punti e punto e virgola sono separatori. Abbiamo aggiunto un ulteriore separatore , “&&”, come separatore dei record. La scelta dei separatori può essere arbitraria a seconde delle esigenze; questo perché potremmo scontrarci con situazioni in cui all’interno dei record utilizzati ci siano proprio i caratteri da noi scelti come separatori, il che porterebbe a risultati imprevedibili. Da qui la necessità di utilizzare o caratteri stravaganti o addirittura sequenze di caratteri improbabili ( difficilmente un dato di database conterrà sequenze tipo “&&&” o “$$$”). Una volta stabilite le regole di traduzione della stringa ricevuta, il modulo parser si occuperà di ottenere una sequenza di dati utilizzabile per la visualizzazione tramite il modulo di interfaccia utente.
A questo punto è plausibile una domanda: ma non sarebbe possibile ( e più semplice) invece di creare un parser, utilizzare il passaggio di dati tramite oggetti serializzabili, le cui interfacce siano disponibili sia all’applet sia all’applicativo server ? Sostanzialmente sì , però abbiamo lo stesso problema che con RMI : compatibilità all’indietro con i browser precedenti. All’interno di una intranet o extranet, dove si possa imporre uno standard tecnologico sicuramente non avremmo alcun problema; potremmo dotare tutti i browser di plugin Java 2 e a quel punto ci potremmo sbizzarrire in un’orgia tecnologica facendo massiccio uso di quello splendido ( e quasi onnipotente) strumento che è JINI, delizia di qualsiasi sviluppatore Java evoluto……..
Passiamo all’applicativo server, del quale possiamo vedere i moduli in figura 3.
 
 

Figura 3

Sono evidenti le analogie con la struttura dell’applet; la gestione dei socket è quasi  la stessa, il parsing viene fatto sui comandi inviati dall’applet per poter formulare una query che verrà indirizzata al modulo JDBC e i dati di ritorno verranno assemblati dal modulo “creazione risposta” per poi essere instradati all’applet. Valgono anche qui le stesse considerazioni fatte per l’applet sia in fase di parsing che in fase di creazione dello streaming di risposta. Il modulo JDBC non fa altro che connettersi al database, lanciare la query ed ottenere un recordset di risposta.
Un’ultima nota sul modulo di gestione dei socket; così come l’abbiamo delineato il server è in grado di servire una sola connessione per volta. Nessun problema: il nostro modulo di gestione del socket provvederà a creare un thread per ogni richiesta , in modo che possano essere processate più richieste contemporaneamente.
 
 
 

Conclusioni
Dovremmo aver toccato tutti i punti che ci servirà esplodere a livello di codice nella prossima parte dell’articolo. La struttura che abbiamo ipotizzato è comunque valida per qualsiasi tipo di applet interfacciato con un application server generico. Utilizzando una grammatica proprietaria è possibile far fare al server qualsiasi tipo di elaborazione e poi ottenerne i risultati sull’applet. Non dobbiamo scomodare il registry rmi , e la soluzione funzionerà su qualsiasi tipo di browser con supporto Java 1.0.2 ( preistoria !!). Lo so, anche io mi strapperei le vesti dallo sdegno ogni volta che mi si pongono limiti tecnologici per mantenere la compatibilità con sistemi dell’era mesozoica, però spesso questo significa anche acquisire una padronanza con meccanismi più a basso livello del linguaggio utilizzato, e la cosa può non essere del tutto negativa alla fine, non fosse altro perché ci porta ad apprezzare di più tutti quegli strumenti che spesso diamo per scontati.
Compitino per il mese prossimo: ripassiamo bene le varie java.Socket.* e java.util.*, delle quali faremo massiccio uso nella scrittura del codice sul prossimo articolo.
 


MokaByte rivista web su Java
MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it