MokaByte Numero 07 - Aprile 1997
di Antonio Viesti 
e
 Billy De Vita

 

Una implementazione di acceso remoto 
a basi di dati relazionali 
via web

 


 


L'accesso remoto a basi di dati relazionali via web è forse una delle applicazioni più interessanti di tecnologie java-based. Questa soluzione consente, se implementata come intranet, di risolvere molti dei problemi tipici delle architetture client/server tradizionali: quelli relativi al processo di installazione, aggiornamento e manutenzione del software client, ed al supporto multipiattaforma. Implementata in internet consente un accesso on-line dinamico via web alle basi di dati aziendali.


In questo articolo definiamo le linee di riferimento di una implementazione di acceso remoto ai dati, in un contesto client/server, che possa essere:

Ci proponiamo di costruire un Data Server che, pilotato da un applet remoto - o da funzioni Javascript inserite nelle pagine web dell'applicazione, possa interrogare la base di dati, impacchettare i risultati in pagine html dinamiche di report, e trasferirle in risposta al web browser.

Lo schema minimo di implementazione è questo:

Allora, procediamo...
 

DataBase, l'interfaccia JDBC alla base di dati.

Costruiamo innanzi tutto una classe, DataBase.class, che implementi i semplici metodi di accesso ai dati via JDBC. Ci si può riferire alle indicazioni contenute nell'articolo di Filippo Bobbi nel numero precedente di MokaByte.

Codifichiamo i metodi essenziali:

un costruttore, che chiama alcuni metodi di inizializzazione dell'accesso ai dati

public DataBase() {

installaJDBCDriver();

apriConnessione();

}

i metodi select e update, di accesso ai dati
public ResultSet select(String sqlquery) {

...

}

public int update(String sqlquery) {

...

}

ed infine un metodo conclusivo

public void chiudiConnessione() {

...

}
 

Le classi specializzate di accesso ai dati:
DataReporter, DataModifier, ...e qualcos'altro.

DataReporter.class: un compilatore di pagine web dinamiche di data report

Costruiamo poi un'altra classe, il DataReporter.class, capace di compilare data reports dinamici, formattati in HTML. I tags html, la <TABLE>, la <PICTURE> e tutti gli elementi del <FORM> danno un'estrema flessibilità alla impaginazione dei dati, ...utilizziamo quindi questi - e non il package awt - per la costruzione dell'interfaccia.

Ci occorre una classe che, leggendo le direttive contenute in un modello astratto di pagina html (un file che - conveniamo - avrà estensione .frm), possa costruire un report dinamico html che incorpori i dati rilevati attraverso query sql dal database. Questo pone il problema di una estensione dell'html: accanto ai tags standard di formattazione della pagina, ci occorrono dei tags estesi di data request (data tags).

Procediamo così. Ipotizziamo di lavorare con una base di dati quasi banale, monotabellare: un archivio bibliografico con i seguenti campi: IDPubblicazione, Titolo, Autore, Editore. Poniamo di voler costruire un report dei titoli, utilizzando quindi la query sql "SELECT Titolo FROM ArchivioBibliografico": potrei estendere i tags html con il nuovo tag <DATATABLE>, più o meno così

<DATATABLE SQLQUERY="SELECT Titolo FROM ArchivioBibliografico ORDER BY Titolo">

<TR>

<TD BGCOLOR="#EEEEEE">

<FONT FACE="Arial" SIZE=2><B>

?

</B></FONT>

</TD>

</TR>

</DATATABLE>

La nostra semplice pagina/modello di report html, chiamiamola ElencoAlfabeticoDeiTitoli.frm, diventerebbe quindi, completata con i tags usuali:
<HTML>

<HEAD>

...

<HEAD>

<BODY BGCOLOR="#FFFFFF">

<FONT FACE="Arial" SIZE=3><B>

Ecco l'elenco dei titoli dell'archivio bibliografico:

</B></FONT>

<DATATABLE SQLQUERY="SELECT Titolo FROM ArchivioBibliografico ORDER BY Titolo">

<TR>

<TD BGCOLOR="#EEEEEE">

<FONT FACE="Arial" SIZE=2><B>

?

</B></FONT>

</TD>

</TR>

</DATATABLE>

</BODY>

</HTML>

Possiamo definire queste estensioni html con estrema libertà e creatività: quel che importa è adottare una sintassi univoca ed inserire, accanto agli elementi di formattazione di pagina html, i riferimenti alle queries sql di accesso ai dati nei data tags. Noi, nelle nostre applicazioni commerciali, abbiamo definito le estensioni html <DATATABLE>, <DATAPICTURE>, <DATALISTBOX> e <DATACOMBOBOX>, poi <DATAOPTION> <DATACHECK>, <DATAINPUT>, ecc.

Abbiamo anche definito una <ACTIVEDATATABLE>. Nella seconda puntata di questo articolo, torneremo a parlare in modo un po' più approfondito di queste estensioni all'html standard.

Adesso ci basti avere tutti i riferimenti per implementare la classe DataReporter.class: questa dovrà costruire un file html di report con una procedura che è quella di copiare ed incollare, dal modello html esteso, i tags html standard, processare invece i data tags e scrivere al loro posto i dati rilevati dal database. Possiamo implementare questa procedura in un macrometodo, che apre il file modello, ne avvia la lettura sequenziale, e ne copia e incolla il contenuto fino a quando non incontra un tag esteso, lo processa, quindi riprende a copiare ed incollare i tags standard fino al prossimo tag esteso, ...e così via.

compilaHTMLReport(String modello)

e in una serie di piccoli metodi specializzati chiamati dal macrometodo per il processo dei tags estesi

writeDataTable()

loadDataPicture()

writeDataListBox()

...

Tutto qui: abbiamo implementato un generatore dinamico di reports html, a partire da un file modello editabile anche con il NotePad di Windows. Le caratteristiche di flessibilità e di configurabilità sono evidenti! Combinando i diversi data tags, possiamo produrre delle pagine di report complesse e strutturate come queste, ad esempio:

DataPage01.htm, DataPage02.htm.

Allora: passando un riferimento ad un modello di report al DataReporter, attiviamo la procedura di costruzione di un report dinamico. Questo riferimento può essere passato da un'applicazione java residente, ma anche da un applet remoto ...no?

La nostra architettura client/server di accesso ai dati si riduce quindi a questo: editare prima tutti i modelli di reporting che utilizzeremo nell'applicazione (li sistemiamo tutti, poniamo, nella cartella ArchivioLibrario/templates/, dal lato server), così che la applet possa ottenere una pagina di report dei dati con il semplice passaggio/trasmissione di un riferimento al modello.

L'applet trasmette il riferimento al modello, ad esempio "ElencoAlfabeticoDeiTitoli", il server cerca il file .frm di modello nella cartella dei templates, lo apre, lo legge, costruisce il report dinamico (ad esempio ElencoAlfabeticoDeiTitoli.htm) che deposita, poniamo, nella cartella ArchivioLibrario /reports/) e comunica all'applet la fine della procedura di data reporting ed il riferimento al file html di report ("ElencoAlfabeticoDeiTitoli"). A questo punto basterà che il browser punti all'URL ArchivioLibrario /reports/ElencoAlfabeticoDeiTitoli.htm

Quelle riportate non sono altro che delle rudimentali linee-guida di implementazione. I limiti di questo articolo non consentono ulteriori approfondimenti. Ma abbozziamo appena uno...

La query utlizzata nell'esempio precedente non è di tipo parametrico. E nel caso, invece, di query con parametri? Ad esempio nel caso di "SELECT Titolo FROM ArchivioBibliografico WHERE Autore = 'Pirandello' ORDER BY Titolo"?

Procediamo così:

inseriamo una sezione <PARAMETERS> nel modello, e in questa elenchiamo delle etichette di parametro (conveniamo, ad esempio, di precederle da un carattere di cancelletto #)

<PARAMETERS>

#Autore

...

</PARAMETERS>

e scriviamo la query sql parametrica utilizzando l'etichetta
SELECT Titolo FROM ArchivioBibliografico WHERE Autore = '#Autore' ORDER BY Titolo
In questo caso occorrerà passare al DataReporter, con il riferimento al modello, anche il valore di parametro ("ElencoAlfabeticoDeiTitoli", "Pirandello")

DataModifier.class: insert, delete, update...

In un'altra classe, il DataModifier, implementeremo i metodi di accesso in scrittura ai dati, ovvero le procedure di insert, delete, update. ...Di questa classe ci occuperemo nella seconda puntata di questo articolo. Lì ci occuperemo pure di come queste linee-guida possano essere utilizzate per la realizzazione di una semplice applicazione di server commerciale on-line. Ci basti al momento tener presente che DataModifier.class è specializzata nel processare l'istruzione (MODIFY, ...) del nostro rudimentale protocollo di accesso ai dati.

...E qualcos'altro.

Per economizzare tempi e risorse, occorrerebbe occuparsi dei problemi di ottimizzazione dell'accesso ai dati. Ad esempio, se un altro utente ha già chiesto un determinato report, che è quindi già disponibile in formato html, e se nel frattempo non sono state effettuate operazioni di aggiornamento dei dati, non occorre accedere al database e ricompilare un file .htm di report, ma basterà passare il riferimento al file esistente. Qundi le richieste di accesso ai dati dovrebbero essere filtrate da una classe, DataCache.class, prima di essere inoltrate al DataReporter. DataCache dovrà verificare che il report richiesto sia disponibile ed in questo caso passare il riferimento allo URL, altrimenti passare la request al DataReporter per la compilazione. DataCache dovrebbe inoltre rimuovere tutti i riferimenti ai report quando questi non sono più attuali, cioè quando sono state effettuate operazioni di aggiornamento dei dati.
 

DataServer: un server di gestione delle classi di accesso ai dati.

Le attività di DataReporter, DataCache, DataModifier devono essere coordinate ed integrate. Ci occorre una classe di controllo (un server), che riconosca il nostro rudimentale protocollo di comunicazione e, in base alle richieste, attivi le classi di accesso ai dati: un DataServer.class.

Se il DataServer riceve, ad esempio, una request di report, di tipo cioè [REPORT, modello, parametri], dovrà provvedere ad inoltrarla a DataCache, quindi a DataReporter, e incaricarsi di trasmettere al richiedente il riferimento allo URL del file di report generato.

Implementiamo schematicamente la classe DataServer così:

class DataServer {

private DataBase DATABASE;

private DataReporter DATAREPORTER;

private DataModifier DATAMODIFIER;

private DataCache DATACACHE;

// metodo costruttore:

public DataServer(DataBase database) {

DATABASE = database;

DATAREPORTER = new DataReporter();

DATAMODIFIER = new DataModifier();

DATACACHE = new DataCache();

}

}

Occorrerà poi implementare i metodi di riconoscimento e di processo delle data requests, di tipo REPORT e di tipo MODIFY. Ad esempio
public String processaRequestDiReport(String modello, String parametri) {

String htmlreportfile;

// verifico se un riferimento al file di report è presente in cache

htmlreportfile = this.DATACACHE.getCachedHTMLReport(modello, parametri);

// se DATACACHE ritorna un riferimento vuoto al file di report

if (htmlreportfile.equals("")) {

// attuo un accesso al database e compilo il file .html di report

htmlreportfile = this.DATAREPORTER.compilaHTMLReport(modello, parametri);

}

// restituisco il riferimento al file di report

return htmlreportfile;

}

public String processaRequestDiModify(...) {

...

}
 

L'architettura di server remoto

Occorre ora implementare questa tecnologia in una architettura di server di accesso remoto. Ci occorreranno le ulteriori classi:

La connessione-utente implementerà:

i due metodi elementari di ricezione e trasmissione di sequenze di caratteri

private String ricevi()

private void trasmetti(String data)

alcuni metodi di inizializzazione della connessione, chiamati dal costruttore,
public RemoteDataAccess () {

connetti();

rilevaUserId();

rilevaPassword();

identificaUtente();

autorizzaAccessoAiDati()

...

}

...ed infine un processo di threading, un ciclo di ricezione di istruzioni di data requests che dovranno essere poi passate al DataServer, attesa della elaborazione delle requests e trasmissione delle relative replies ottenute in risposta, fino alla disconnessione
public void run() {

boolean running;

running = true;

String request; // (REPORT ...), (MODIFY ...), oppure (DISCONNECT)

String reply;

while (running) {

request = ricevi();

if (request.equals("DISCONNECT ")) {

running = false;

}

else {

reply = this.DATASERVER.replyTo (request);

trasmetti(reply);

}

}

disconnetti();

}

un metodo conclusivo

private void disconnetti() {

...

}
 

Start !

Abbiamo costruito tutto quello che ci occorre dal lato server. Possiamo ora avviare l'applicazione.

Istanziamo la classe DataBase:

Database ArchivioBibliografico;

ArchivioBibliografico = new Database();

istanziamo la classe DataServer, passandole il riferimento alla classe DataBase di interfaccia ai dati: DataServer costruirà le sue classi di servizio DataReporter, DataCache, DataModifier:
DataServer ArchivioBibliograficoDataServer;

ArchivioBibliograficoDataServer = new DataServer(ArchivioBibliografico);

istanziamo il server di monitoraggio delle richieste di connessione remota:
RemoteDataAccessServer ArchivioBibliograficoAccessServer;

ArchivioBibliograficoAccessServer = new RemoteDataAccessServer();

...e restiamo in attesa di connessioni remote.
 

DataApplet: un semplice applet di accesso ai dati.

DataApplet.class: un semplice applet di accesso ai dati...

L'applet-client, DataApplet.class, si limiterà a trasmettere - oltre ai riferimenti iniziali a UserID e Password di connessione, e ad un flag di disconnessione alla fine del collegamento - data requests secondo il protocollo che abbiamo definito, e restare in attesa dal server dei riferimenti ai files .htm, nel caso di requests di tipo REPORT, o flag d'esito, nel caso di requests di tipo MODIFY. Nella sua versione più semplice, dovrà implementare

i due metodi elementari di ricezione e trasmissione di sequenze di caratteri

private String ricevi()

private void trasmetti(String data)

un metodo di inizializzazione della connessione
public void start() {

connetti();

}

un metodo di disconnessione, che dovrà comunicare al server la fine del collegamento:
public void stop() {

trasmetti("DISCONNECT");

}

...anche attraverso Javascript.

L'accesso remoto ai dati potrà avvenire anche attraverso Javascript, incapsulando i metodi ricevi() e trasmetti() dell'applet in due corrispondenti funzioni Javascript:

<SCRIPT>

function trasmetti(data) {

document.DataApplet.trasmetti(data);

}

function ricevi() {

return document.DataAccessApplet.ricevi();

}

</SCRIPT>
 

Antonio Viesti e Billy De Vita lavorano a Tiresia Informatica, studio associato di consulenze e produzioni informatiche aziendali di Bari.

Hanno prodotto - progettando l'implementazione di acceso remoto a basi di dati riferita in questo articolo (denominata AIDA, Advanced Internet / Intranet Data Access) - i packages commerciali: 

  • AIDA Biblio, un sistema intranet di accesso remoto ad un database bibliotecario per la consultazione del catalogo librario e la gestione dei prestiti (in ambiente server Windows NT); 
  • AIDA P4 Commerce Server, un package di spazio espositivo e punto vendita on-line in internet. 
Attualmente stanno lavorando al progetto APULIA Days, sistema informativo internet di accesso ad una base di dati delle strutture di ricezione turistica della Puglia.

Possono essere contattati alle mailboxes antonioviesti@tiresia.it, billydevita@tiresia.it, o attraverso Tiresia Informatica (http://www.tiresia.it). 

 
 

MokaByte rivista web su Java

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