Home   |   Archivio   |   Chi siamo   |   Contatti
Mauro Molino
JDBC e WEB
I parte
di
Mauro Molino
L'implementazione di un applet che legga e 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

Parliamo di applet che accedono ad un database remoto. L'argomento si presta bene ad una piccola serie di articoli, perché coinvolge diversi aspetti della programmazione Java: socket, parsing, JDBC, compatibilità tra versioni delle virtual machine e progettazione di una piccola architettura client-server.

Il punto di partenza è semplice: vogliamo un applet che venga eseguito nel browser del client, ma che possa interrogare un database remoto senza affidarsi a tecnologie che richiedono browser troppo evoluti o plug-in non sempre disponibili.

Le alternative

Vista la situazione abbiamo comunque bisogno di uno strato intermedio tra la nostra pagina Web e il database. Per parlare di ciò che è già pronto possiamo subito dare un'occhiata al Remote Scripting, una tecnologia Microsoft in grado di eseguire funzioni lato server e restituire dati al client.

Riportiamoci però ad un mondo più "Java puro": se parliamo di accesso remoto a qualcosa la prima sigla che ci viene in mente è RMI. Il problema è che poche sono le VM integrate nei vari browser in grado di gestire RMI in maniera decorosa, per cui spesso questa ipotesi va scartata.

Un'altra possibilità è una connessione pura TCP/IP fra applet e processo server con interscambio di dati. In questo primo articolo faremo un'analisi approfondita dell'architettura per poi, nei prossimi, lanciarci nella scrittura del codice.

Analisi preliminare

Come mostrato in figura 1, abbiamo tre entità distinte: il nostro applet, un applicativo server e un database.

Figura 1: Struttura generale del progetto
Figura 1: Struttura generale del progetto

L'applet viene naturalmente eseguito sul client, mentre l'applicativo server risiede sul web server. 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 il bridge JDBC-ODBC.

Questa scelta non è necessariamente la più elegante, ma permette di ragionare sull'architettura di base senza introdurre ulteriori complessità. Quello che ci interessa qui è scomporre il problema in blocchi funzionali semplici e compatibili con browser che supportano soltanto Java 1.0.2.

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: Blocchi funzionali dell'applet
Figura 2: Blocchi funzionali dell'applet

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, dove 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 e output e di instradare e 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 seconda 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 facendo massiccio uso di strumenti ben più moderni.

Passiamo all'applicativo server, del quale possiamo vedere i moduli in figura 3.

Figura 3: Blocchi funzionali dell'applicativo server
Figura 3: Blocchi funzionali dell'applicativo server

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.

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.net.Socket. e java.util., delle quali faremo massiccio uso nella scrittura del codice sul prossimo articolo.

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it