Skip Navigation LinksHome : Articoli : Microsoft Access, COBOL e XML per realizzare uno spooler di stampa

Microsoft Access, COBOL e XML
per realizzare uno spooler di stampa

di Gionata Aladino Canova e Paolo Rivieri (VBJ 78)

Realizzare tanto, con poco sforzo, grazie alla potenza degli strumenti che abbiamo oggi a disposizione

Introduzione

L'articolo nasce descrivendo la realizzazione di una soluzione software creata a 4 mani. Il dott. Paolo Rivieri è stato titolare per 25 anni della TDE Center srl, azienda che ha fondato il suo business sullo sviluppo del software, la quasi totalità del quale è stato creato in COBOL, nei suoi diversi dialetti. Svariate procedure sono utilizzate ancora oggi con piena soddisfazione degli utenti. Un problema che si fa sempre più pressante è però quello delle stampe. Nell’ultimo decennio, le tecnologie di stampa sono cambiate drasticamente e le stampanti ad aghi sono quasi scomparse. L'uso del modulo continuo ha senso ormai, soltanto dove si abbia bisogno di più copie, magari su moduli prestampati o bollati. In tutti gli altri casi, una stampante laser risolve egregiamente qualsiasi necessità di stampa. Proprio per questo, presso alcuni clienti, è nata l'esigenza di aggiornare il sistema di stampa senza però dover convertire l'intero software sviluppato. Presso alcuni clienti era stata implementata anche una soluzione che consisteva nel disegnare un modulo in PCL grazie a programmi appositi. Delle macro fondevano poi il modulo e l'output del programma COBOL, inviando il tutto alla coda di stampa. A parte le notevoli difficoltà legate alla modifica delle stampe, il tutto richiedeva comunque una stampante PCL. Recentemente, abbiamo sviluppato una soluzione software, tutto sommato molto semplice, che risolve tutti i problemi illustrati, consentendo di toccare il meno possibile i sorgenti COBOL, di utilizzare qualsiasi stampante a disposizione e di modificare facilmente i report.

L'importanza dell'analisi e della progettazione, ieri ed oggi

L'analisi e la progettazione del software sono sempre stati fondamentali. Ma, nel passato ed oggi, lo sono per motivi diversi. Quando in passato si utilizzavano linguaggi poco espressivi, una buona analisi ed un'accurata progettazione erano essenziali per arrivare in fondo al lavoro. Procedure anche banali potevano produrre migliaia o decine di migliaia di righe di codice. Oggi abbiamo a disposizione strumenti molto potenti e linguaggi altamente espressivi. Chi ha programmato in qualsiasi linguaggio procedurale, senza fare uso particolare di librerie per la gestione dati, ed ha provato a gestire un archivio, ha un'idea della differenza che passa tra un'istruzione SQL e decine o centinaia di istruzioni di un linguaggio come il C, per eseguire lo stesso compito. Tuttavia oggi, l'analisi e la progettazione sono importanti per scegliere la soluzione più efficace. Adottare un linguaggio, uno strumento o un protocollo al posto di un altro, può portare ad aumentare enormemente i tempi di sviluppo o di debug. Quindi, a differenza di una volta, è più facile comunque arrivare a completare il lavoro, ma perché sprecare tempo, fatica e soldi? Vediamo quali sono state le scelte vincenti per la nostra soluzione.

XML come collante

Nel nostro caso non aveva senso pensare di leggere direttamente i file dati COBOL, cosa per altro fattibile per alcuni dialetti con appositi driver. Infatti, i programmi che stampano bolle e fatture fanno spesso elaborazioni anche complesse. Quindi, la nostra attenzione si è accentrata su di essi. Catturare semplicemente il loro output avrebbe reso semplice la modifica dei sorgenti COBOL, ma avrebbe complicato il recupero dei dati. In COBOL, la soluzione naturale per l’esportazione dati è fare un file ASCII delimitato. Il problema di questa soluzione è che il recupero dei dati si presenta ancora una volta complesso. Infatti, una fattura è composta, almeno, da una intestazione, dalle righe di dettaglio e da un pié di pagina. Quindi si sarebbe reso necessario un parsing del file per estrapolarne i diversi elementi. Inoltre, cambiando qualsiasi cosa nell'output del programma COBOL, si sarebbe reso necessario il contemporaneo aggiornamento del programma che legge i dati.

Qui entra in gioco l'XML. I punti di forza sfruttati dell'XML sono:

  • Il file contiene sia i dati che i metadati
  • Il file contiene più entità; ad esempio, l'intestazione e le righe di dettaglio

Nel nostro caso, abbiamo realizzato una sezione in cui memorizziamo le informazioni relative al report da stampare, alla stampante da utilizzare e al numero di copie; una sezione relativa ai dati del documento ed una relativa alle righe. Vedremo tra poco i dettagli.

 

Scelta dell'applicazione per realizzare lo spooler

Il sistema è stato realizzato in Microsoft Access XP. La scelta è stata dettata dalla facilità con cui, in Microsoft Access si possono gestire i report. Il VBA consente di gestire agevolmente l'importazione dei file XML e qualsiasi elaborazione eventualmente richiesta sui dati. Qualsiasi strumento di alto livello con un generatore di report, come Visual Studio, sarebbe comunque stato adatto.

Realizzazione del programma COBOL

Dal lato COBOL, la parte del sistema che va realizzata è sostanzialmente una conversione delle routine di stampa già esistenti. In pratica, si prendono i programmi di stampa e si aggiungono le istruzioni che servono per realizzare la struttura del file XML e per scrivere il tutto su un file di testo, anziché su una stampante. Una facilitazione sta nel fatto che non servono rotture di codice per la gestione del salto pagina. Eventuali elaborazioni possono essere spostate sul report realizzato in Access. Sarebbe, anzi, dannoso, se ci fossero. Infatti cambiando semplicemente margini al report, potrebbe essere che le righe contenute in una pagina cambino, invalidando tutti i conti fatti in COBOL per il salto pagina.

Una complicazione sta nel fatto di dover aprire e chiudere i tag relativi all'intero file, alle sezioni ed ai singoli campi. Poiché l’apertura e la chiusura di un tag possono essere distanti all’interno del codice sorgente, è necessario tenerne conto in fase di scrittura del programma, prevedendo magari subroutine che aprano e chiudano i tag.

Per fare mente locale, una stampa di 3 copie, con una riga di intestazione ed una riga di dettaglio, come da esempio:


TDE Informatica srl

0001 Realizzazione articolo per VBJ    € 10


va tradotta in XML in

<Radice>
    <XMLImpostazioniStampa>
        <NumeroCopie>3</NumeroCopie>
    </XMLImpostazioniStampa>
    <XMLDocumento>
        <Campo001>TDE Informatica srl
    </Campo001>
    </XMLDocumento>
    <XMLRigaDocumento>
        <Campo0>001</Campo0>
        <Campo1>Realizzazione articolo per VBJ
    </Campo1>
    <Campo2>€ 10</Campo2>
    </XMLRigaDocumento>
</Radice>

Un esempio completo, aperto in un editor XML è visibile in Figura1


Figura 1

I caratteri speciali

L'XML è un formato molto rigido. Nella parte che contiene dati, sono vietati molti caratteri, tra cui, ad esempio, l'apostrofo. Ovviamente, la nostra terza stampa di prova conteneva un apostrofo nel nome della ditta... Le soluzioni sono essenzialmente due. La prima consiste nell’alterare il programma COBOL aggiungendovi una routine che converte i caratteri speciali con la corrispondente stringa valida. Ad esempio, l'apostrofo diventa &apos;. Le specifiche di XML prevedono esplicitamente anche la possibilità di utilizzare la codifica Unicode per rappresentare i caratteri non latini, come ad esempio i caratteri greci, cirillici, gli ideogrammi cinesi e giapponesi.  Il problema principale di queste soluzioni è che, ad un carattere, corrisponde una stringa di più caratteri e quindi, avendo il COBOL dei campi a spaziatura fissa, va gestito l'eventuale overflow che si potrebbe avere nella conversione.

Una soluzione molto più efficiente, per cui ringraziamo la dottoressa Renata Bandelloni, è affidarsi ad una caratteristica dell'XML (1) che consente di specificare qualsiasi carattere all'interno di un blocco ben delimitato.

Nel codice seguente

<codice>
   <![CDATA[
      <libro>
         <capitolo>Questo capitolo contiene € e ‘
         </capitolo>
      </libro>
   ]]>
</codice>

tutto quello che è incluso nel tag ![CDATA[ viene ignorato, dal punto di vista del controllo sintattico. Ovviamente, in COBOL, la via più veloce per risolvere tutti i problemi di caratteri particolari è proprio questa. Si scrive nel file il tag di apertura, si lascia invariato il codice che scrive dati e si chiude il tag.

Realizzazione dello Spooler

La struttura dello spooler è semplice. Un timer provvede, ad intervalli regolari, a fare una scansione di una cartella, specificata in un parametro. Se vengono trovati nuovi file, vengono importati in una lista. La lista viene ordinata e poi i file vengono aggiunti ad una listbox. L’interfaccia dell’applicazione è visibile in Figura 2.


Figura 2

L'ordinamento si è reso necessario quando vi sono stampe consecutive, come nel caso della fatturazione riepilogativa. È necessario preservare l'ordine di uscita dei file da COBOL. Per fare questo, il nome dei file COBOL contiene la data e l'ora in formato yyyymmgghhssxx più un numero progressivo che consente di non sovrascrivere file stampati nello stesso secondo.

La scelta del timer è dettata da ragioni di semplicità. Si potrebbe pensare di utilizzare le API con delle funzioni di callback per avere notifica dal sistema operativo della presenza di nuovi file, ma il beneficio ottenuto sarebbe veramente minimo a fronte di una notevole complicazione del codice e di un più difficile debug.

Il comando Application.ImportXML importa un file xml. La cosa interessante è che esso crea una tabella per ogni entità di primo livello. Quindi, scegliendo con criterio il nome degli oggetti di primo livello, ci risparmiamo un po' di lavoro. Ogni nostro oggetto inizia con il prefisso "XML". La scelta è dovuta al fatto di poter cancellare le tabelle importate senza averne un elenco preventivo. La routine seguente

For Each tbl In CurrentData.AllTables
    If Left(tbl.Name, 3) = "XML" Then
        CurrentProject.Connection.Execute "DROP TABLE " & tbl.Name
    End If
Next   

provvede all'eliminazione delle tabelle importate. Visto che il programma deve essere il più robusto possibile, se un'importazione fallisce a metà o se il file contiene informazioni errate, ci garantiamo, entro certi limiti, di ripulire sempre bene il nostro database, prima di una nuova importazione.

La prima tabella creata, XMLImpostazioniStampa, contiene le informazioni sulla stampante da utilizzare, il numero di copie da stampare e il report da utilizzare. Il nome della stampante è associato, tramite la tabella tblStampanti alla reale stampante Windows da utilizzare. A questo punto, è sufficiente accordarsi su un nome di comodo per indicare una certa stampante e selezionarla poi effettivamente da Windows, come illustrato in Figura 3.


Figura 3
Nel caso in cui la stampante venga cambiata, il programma COBOL non viene toccato. Il nome del report consente al programmatore COBOL di selezionare il report che verrà utilizzato per la stampa. Quindi, per aggiungere la stampa di una DDT, si crea un nuovo report in Access ed il programmatore COBOL dovrà soltanto richiamarlo.

La seconda tabella creata,  XMLDocumento, contiene i dati di testa e di fondo pagina del documento. Normalmente, conterrà un solo record, mentre la terza tabella,  XMLRigaDocumento, contiene tanti record per quante sono le righe di dettaglio del documento. In entrambe le tabelle, si è scelto di dare un nome sequenziale ai campi (campo001, campo 002...).

Installazione del sistema

L'installazione del sistema si divide in due fasi, la parte relativa al COBOL e la parte relativa ad Access. Nel nostro caso, le procedure COBOL giravano su un server UNIX, che è il caso più complesso. Dopo aver messo su i programmi modificati, si deve fare in modo che i file generati siano visti da Windows. O si condivide una cartella sul server, dopo aver installato un programma tipo Samba per renderla visibile da Windows, o si crea una procedura che copia i file su una cartella condivisa di un pc Windows, che è la strada da noi seguita.

Sul pc Windows si installa il programma scritto in Access, con l'eventuale runtime se necessario. Per chi ancora non lo sapesse, il runtime di Access 2007 è diventato gratuito (2). Poi, dal programma stesso, si impostano le stampanti e la cartella da cui leggere i file. Infine si spera bene... J

Il risultato finale che deriva dal file di prova è quello visibile in Figura 4.


Figura 4
L'applicazione completa è scaricabile qui.

Conclusioni

Oggi più che mai è necessario, di fronte ad un problema, staccare le mani dal pc e fermarsi a riflettere su quali strade sono percorribili. Sono utilissimi anche confronti con colleghi che hanno specializzazioni diverse dalle nostre, proprio perché potrebbero suggerire approcci alla soluzione del problema radicalmente diversi dai nostri. Sempre più problemi possono essere risolti senza scrivere righe di codice o scrivendone pochissime. Ma bisogna aver imboccato la strada giusta all’inizio…

Un ringraziamento va a Paolo Rivieri che, pur essendo in pensione e pensando alla sua barca a vela, ha trovato il tempo per scrivere un programma in COBOL ridotto al massimo, da utilizzare come esempio per VBJ.

 

Riferimenti

1) http://xml.html.it/guide/lezione/1843/documenti-ben-formati/

2) http://office.microsoft.com/it-it/access/HA102188641040.aspx