Faina Biomedica
Codice Dispatcher sistema ad eventi
Cos'è
il Software Libero?
Il
“Software Libero” è una questione di libertà, non di prezzo.
Per capire il concetto, bisognerebbe pensare alla “libertà di
parola” e non alla “birra gratis”. (NdT: il termine “free”
in inglese significa sia gratuito che libero).
L'espressione
“Software Libero” si riferisce alla libertà dell'utente di
eseguire, copiare, distribuire, studiare, cambiare e migliorare il
software. Più precisamente, esso si riferisce a quattro tipi di
libertà per gli utenti del software:
Libertà di eseguire il
programma, per qualsiasi scopo (libertà 0).
Libertà di studiare
come funziona il programma e adattarlo alle proprie necessità
(libertà 1). L'accesso al codice sorgente ne è un
prerequisito.
Libertà di ridistribuire copie in modo da aiutare
il prossimo (libertà 2).
Libertà di migliorare il programma e
distribuirne pubblicamente i miglioramenti, in modo tale che tutta la
comunità ne tragga beneficio (libertà 3). L'accesso al codice
sorgente ne è un prerequisito. ...
Open source is a
development method for software that harnesses the power of
distributed peer review and transparency of process. The promise of
open source is better quality, higher reliability, more flexibility,
lower cost, and an end to predatory vendor lock-in.
The Open
Source Initiative (OSI) is a non-profit corporation formed to educate
about and advocate for the benefits of open source and to build
bridges among different constituencies in the open-source community.
One of our most important activities is as a standards body,
maintaining the Open Source Definition for the good of the community.
The Open Source Initiative Approved License trademark and program
creates a nexus of trust around which developers, users, corporations
and governments can organize open-source cooperation. ....
Qui vi segnalo alcuni software open source
Open Office: utilissimo pacchetto office completo dell'equivalente di word, excelle, power point.
Octave: ambiente equivalente e compatibile con matlab.
Sapevo dell'esistenza di un software equivalente a Matlab ovvero di Octave ma non l'avevo mai preso in considerazione. Questi giorni l'ho guardato con più attenzione e per quello che serve a noi a elaborazione dei segnali biomedici è sufficiente.
Potete scaricarlo sia per windows che per linux al sito http://sourceforge.net/project/showfiles.php?group_id=2888.
Per maggiori informazioni sul software guardare il sito http://www.gnu.org/software/octave/.
Per i tool che si possono aggiungere guardare il sito http://octave.sourceforge.net/packages.html.
Linux: sistema operativo open source per antonomasia (http://www.linux.it/).
Ubuntu: sistema linux tra i più semplici e affermati (http://www.ubuntu-it.org/).
Ho sviluppato la tesi del terzo anno su care2x un His open source scritto in php. Questo software è completo ma è molto difficile da usare.
Ho guardato anche lo standard DICOM durante lo sviluppo di una relazione per un esame. Questo è uno standard usato per i risultati della diagnostica per immagini. Non definisce un formato per le immagini me piuttosto un modo standard per trattarle.
Ho sviluppato un sistema ad eventi per collegare tra loro i vari sistemi presenti in una struttura sanitaria per la tesi del V anno.
Errori tipici incontrati nel lavorare con Linux
!# /bin/bash^M
Non riuscivo a capire perché non mi girava il file.sh, mi dava questo errore, lo aprivo con un normale editor di testo e non vedevo niente di anomalo. Allora come ultima prova lo ho aperto con vi da linea di comada e magicamente sono spuntati fuori i sipoli “^M” alla fine di ogni riga.
Possono essere aggiunte inserendo le linee “export NOME_VARIABILE=valore” nel file .bashrc;
La variabile d'ambiente “PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:” indica le directory dove sono contenuti gli eseguibili dei vairi programmi che possono essere chiamati da linea di comando.
Se non esistono i driver per linux bisogna usare quelli per windows. Dopo averli scaricati da internet li decomprimiamo e individuiamo il file.inf all'interno della cartella decompressa.
Ora installiamo ndisreapper e poi digitiamo i seguenti comandi:
cd /the_dir_you_put_the_wlan_drivers_into/
sudo ndiswrapper -i bcmwl5.inf (fill out your own drivers for bcmwl5.inf)
sudo ndiswrapper -l (shows if the driver is installed)
sudo modprobe ndiswrapper
sudo dmesg (shows that the card is installed (hopefully))
sudo iwlist wlan0 scan (shows all APs surrounding you)
sudo ndiswrapper -m
sudo iwconfig wlan0 essid name_of_AP (the name you found by using iwlist wlan0 scan)
iwconfig wlan0 enc <key> (fill out your WEP key (if you have one))
sudo dhclient wlan0 (gets a dynamic IP adress)
sudo ping -c 3 www.ubuntu-linux.nl (tests the connection)
Per maggiori informazioni guarda il seguente forum: http://ubuntuforums.org/showthread.php?t=31926.
GNUMed
http://www.vondoczudoc.de/viewtopic.php?t=718
Pacchetti Synaptic:
gnumed-common, gnumed-client
Per quanto riguarda il server bisogna
installare: postgresql-8.1 postgresql-client-8.1 postgresql-doc-8.1
pgadmin3 pgagent python-pgsql python-psycopg2 python-glade-1.2
python-glade2 glade gimp.
Ora da linea di comando digitiamo
sudo
su postgres -c psql postgres
e poi
ALTER USER postgres WITH
PASSWORD 'password' ;
questo ci servirà per settare la password
di postgresql
Ora bisogna lanciare il file
net_install-gnumed_server.sh
A questo punto installiamo con
Synaptic pgadmin3.
Lanciamo PGAdmin III dal menu di Kde poi vai su
File e quindi add a New Server
ora compila i campi
'address'(localhost), 'description', and 'password'.
Ora
modifichiamo il file di configurazione di postgresql come indicato
nel sito http://wiki.gnumed.de/bin/view/Gnumed/Configurepostgresql
Apriamo il file /etc/postgresql/8.3/main/pg_hba.conf e poi
Add
the three lines below, placing them
* toward the end of the
"local" section, meaning after the line " local all
postgres ident sameuser "
* but just before the line "
local all all ident sameuser "
# allow anyone knowing the
proper password to
# log into our GNUmed databases
local
samegroup +gm-logins md5
Ora modificare il file gnumed.con della
cartella .gnumed all'interno della tua home:
# GNUmed system-wide
configuration file
#
-------------------------------------------------------------
#
see also: http://wiki.gnumed.de/bin/view/Gnumed/ConfigFiles
#
-------------------------------------------------------------
#
[]
[profile public GNUmed database]
host =
salaam.homeunix.com port = 5432
database = gnumed_v8
#
GNUmed system-wide configuration file
#
-------------------------------------------------------------
#
#
see also: http://wiki.gnumed.de/bin/view/Gnumed/ConfigFiles
#
#
-------------------------------------------------------------
[workplace]
#
This name is used to describe the workstation at the
# business
logic level, eg. "ultrasound room machine 1",
#
#
Many configuration options stored in the backend
# are tied to
this name.
name = GNUmed Default
[backend]
#
during login the user can chose from several
# profiles defining
which GNUmed database server
# to connect to,
#
# the
profiles themselves are defined further below
#
profiles =
$profiles$
public GNUmed database
local GNUmed
database
$profiles$
[profile public GNUmed
database]
host = salaam.homeunix.com
port = 5432
database =
gnumed_v8
#encoding = UTF8
[profile local GNUmed
database]
host = localhost
port = 5432
database =
gnumed_v8
#encoding = UTF8
MySQL
Trigger
Nel nostro sistema ad eventi è necessario che i vari
sistemi locali inviino a Mirth gli eventi in automatico appena sono
generati. Spesso però questi sistemi non hanno gli strumenti per
farlo. A questo proposito ci viene in aiuto MySQL (certo questo
metodo può essere usato solo qual'ora il software sia sviluppato sul
database MySQL).
Dalla versione 5.0 di MySQL è stato inserito in
questo DBMS un tool per creare notifiche all'accadimento di
eventi.
Per generare queste notifiche è necessario il seguente
scrip:
CREATE TRIGGER trigger name { BEFORE | AFTER }
{ INSERT
| UPDATE | DELETE }
ON table name
FOR EACH ROW
triggered SQL
statement
trigger name: nome arbitrario del trigger;
BEFORE:
indica se lo statement SQL deve essere eseguito prima l'accadimento
dell'evento;
AFTER: indica se lo statement SQL deve essere
eseguito dopo l'accadimento dell'evento;
INSERT: è l'evneto di
insersione di un record;
UPDATE: è l'evento di aggiornamento di
un record;
DELETE: è l'evento di cancellazione di un record;
ON
table name: indica il nome della tabela dove avviene
l'evento;
triggered SQL statement: qui deve essere inserito lo
statement SQL che va eseguito all'accadimento dell'evento.
I
trigger che servono a noi sono quindi:
create trigger
nome_trigger
before insert on nome_tabella
for each row
set
new.nome_colonna_stato = valore1;
Questo va fatto per ogni tabella
di cui vogliamo notificare l'inserimento di un record. Se vogliamo
notificare l'evento di modifica o cancellazione di un record basta
sostituire insert con delete o update.
Inoltre è essenziale che
ogni tabella abbia un campo per lo stato.
Appena Mirth ha
prelevato i record con il valore della colonna stato uguale a valore1
bisogna immediatamente cambiare valore1 con un nuovo valore il che
renderà possibile distinguere i record già prelevati da quelli non
ancora prelevati. Per fare quest'ultima cosa è essenziale che da
Mirth eseguiamo lo statement SQL:
update nome-tabella set
nome_colonna_stato = valore2;
DCMTK è una raccolta di librerie e applicazioni che implementano gran parte dello standard DICOM. Questa raccolta include software per esaminare, costruire e convertire i file di immagini DICOM, inviare e ricevere immagini attraverso la rete, salvare file e software che fungono da worklist server. DCMTK è scritto in un misto di C e C++, è open source.
Questa raccolta è usata da ospedali e compagnie nel mondo per una vasta gamma di applicazioni che vanno dal test di software, alla ricerca, prodotti commerciali e prototipi.
Il software DCMTK può essere compilato sotto windows e sotto una vasta gamma di sistemi Unix incluso Linux, Solaris, QNX, IRIX, Free/Net/OpenBSD e MacOSX.
DCMTK include i programmi DICOM SCP (Service Class Provider = server) e i SCU (Service Class User = Client).
Ecco i software contenuti nella raccolta:
dcm2xml: Converte i file DICOM in file XML
dcmconv: Converte i file DICOM codificati
dcmcrle: Converte i file DICOM nella sintassi di trasferimento RLE[1]
dcmdata: Una libreria e un applicazione per codificare/decodificare dati
dcmdrle: decodifica i file DICOM compressi con l'RLE
dcmdump: Dump DICOM file and data set
dcmftest: testa se il file usa la parte 10 del formato DICOM [2]
dcmgpdir: Create a general purpose DICOMDIR[3]
dcmodify: Modifica i file DICOM
dump2dcm: Converte da ASCII a DICOM
pdf2dcm: Converte da PDF a DICOM
xml2dcm: COnverte da XML a DICOM
dcm2pnm: Converte le immagini DICOM in PPM/PGM, PNG, TIFF o BMP
dcmimage: fornisce un supporto a dcmimgle per le immagini a colori
dcmquant: Converte le immagini DICOM a colori in palette color
dcmscale: Scale DICOM images
dcmdspfn: esporta le curve standard in un file di testo
dcmimgle: una libreria per il processamento delle immagini e un applicazione
dcod2lum: Converte le caratteristiche di una curva plottata in un formato softcopy
dconvlum: COnverte i file VeriLUM in DCMTK display files
dcmcjpeg: Codifica i file DICOM nella sintassi di trasferimento JPEG
dcmdjpeg: Decodifica i file DICOM compressi con JPEG
dcmj2pnm: Converte le immagini DICOM in PGM, PPM, BMP, TIFF o JPEG
dcmjpeg: Libreria e utility per comprimere e decomprimere
dcmmkdir: Crea un file DICOMDIR
dcmnet: una libreria e applicazione di rete
echoscu: verificatore DICOM (C-ECHO) SCU
findscu: DICOM query (C-FIND) SCU
movescu: recupera file DICOM (C-MOVE) SCU
storescp: DICOM storage (C-STORE) SCP
storescu: DICOM storage (C-STORE) SCU
termscu: DICOM termination SCU
dcmmkcrv: Aggiunge curve 2D all'immagine
dcmmklut: Crea una tabella della struttura DICOM
dcmp2pgm: Legge le immagini DICOM e presenta lo stato e il render bitmap
dcmprscp: gestisce le stampe in scala di grigio i DICOM (SCP)
dcmprscu: Stampa i spooler presentation state [4] viewer
dcmpschk: Tool di check per il presentation state
dcmpsmk: Crea una softcopy in scala di grigi del presentation state
dcmpsprt: legge le immagini DICOM e il presentation states e li associa in un print job
dcmpsrcv: Network receive for presentation state viewer
dcmpssnd: Invia sulla rete il presentation state al visualizzatore
dcmpstat: Una libreria e aplicazione per il presentation state
dcmqrdb: Un database server per immagini
dcmqridx: Registra un immagine DICOM in un image database index file
dcmqrscp: archivio di immagini DICOM (central test node)
dcmqrti: The Terminal Initiator Telnet Client Program
dcmsign: libreria e applicazione per la firma digitale
dcmsign: Firma e verifica i file DICOM
dcmsr: a structured report library and utility apps
dsr2html: Converte i file DICOM SR [5] in HTML
dsr2xml: Converte i file DICOM SR in XML
dsrdump: Dump per file DICOM SR
xml2dsr: Converte i file DICOM SR in XML
dcmtls: security extensions per la libreria di rete
dcmwlm: a modality worklist database server
wlmscpfs: Worklist Management DICOM (SCP)
Implementiamo il nostro PACS
Salvataggio
storescp: Resta in attesa di ricevere file DICOM e quando arrivano li salva in una cartella (car1)
storescu: Invia file DICOM a storescp
Es.
storescp -od car1/ 8788
storescu -d localhost 8788 IM-0001-1624.dcm
Converte da DICOM a XML
* dcm2xml
dcm2xml IM-0001-1624.dcm IM-trasformato.xml
Nel file xml abbiamo stringhe del tipo:
<element tag="0008,1010" vr="SH" vm="1" len="8" name="StationName">CT54023</element>
Per estrarre una stringa da un file e metterla in una variabile d'ambiente si devi digitare:
val=$(head -1 nomefile)
Per trovare i file che contengono un certo valore digitiamo il seguente comando:
grep -l "%stringa%" %path ricerca% --> mostra il nome di tutti i file che contengono quella stringa.
Nel caso in cui abbiamo estretto la stringa da un file come visto sopra facciamo:
grep -l $val *.xml
Analisi del nostro sistema PACS
Una volta che un file arriva a storescp viene messo nella cartella scelta (car1).
Con un programma che si attiva ad intervalli regolari andiamo a convertire in formato xml tutti i file presenti nella cartella car1 e il risultato della conversione lo mettiamo in car2, il nome del file convertito è lo stesso di quello originale. Per evitare che al prossimo caricamento del programa si vadano a convertire gli stessi file spostiamo i file originali da car1 a car3.
Con lo script sotto trovo i nuovi file inviati per lo stoccaggio e una volta individuati li converto in xml in modo che poi li posso andare a ricercare:
script_converti.sh
#!/bin/sh
find car1 -type f | wc -l > num_file
val=$(head -1 num_file)
ls -l car1 --sort=time > elenco_file_ordinato_per_data
cat elenco_file_ordinato_per_data | awk '{print $8}'> nomi_file_ordinati_per_data
sed 1d nomi_file_ordinati_per_data > nomi_file_ordinati_per_data_0
count=0
n=$val
echo $n
until [ $n -eq 0 ]
do
n=$(($val-$count))
nome_file=$(head -1 nomi_file_ordinati_per_data_$count)
echo $nome_file > nome_file_$count
sed 1d nomi_file_ordinati_per_data_$count > nomi_file_ordinati_per_data_$(($count+1))
dcm2xml car1/$nome_file car2/$nome_file
cp car1/$nome_file car3/$nome_file
rm car1/$nome_file
count=$(($count+1))
done
Questo script va eseguito solo se val >0.
Script per cercare una stringa in un file xml:
script_cerca.sh
#!/bin/sh
val=$(head -1 nomefile_contenente_stringa_da_cercare)
grep -l $val *.xml > file_che_contiene_il_nome_del_file_dicom_trovato
[1]
RLE
In informatica, l'algoritmo Run-length encoding (RLE) è storicamente il primo algoritmo di compressione per le immagini inventato, utilizzato nei fax ben prima che le elaborazioni grafiche al computer fossero un'attività comune. L'RLE è lossless (senza perdita di informazioni), ovvero permette di comprimere e decomprimere senza alcuna perdita di informazione.
Solitamente si applica alle immagini e si fonda sull'assunto che l'immagine abbia pochi colori, ma può essere utilizzato su qualunque file dove si trovino lunghe sequenze dove lo stesso byte viene ripetuto. La compressione RLE viene spesso impiegata anche nei protocolli di rete (ad esempio, IBM SNA) o nei formati di dati di applicazioni in cui il tempo di elaborazione è critico (ad esempio, alcuni filmati AVI), perché è il formato che permette la maggior velocità di decompressione.
L'algoritmo di RLE cerca nei dati da comprimere una serie di elementi uguali (in un'immagine bitmap, essa corrisponde ad una campitura piatta), e la sostituisce con un solo elemento, quindi un carattere speciale e infine il numero di volte che esso va ripetuto. Per esempio supponiamo di avere un'immagine dove la prima riga è formata da cento pixel neri, il RLE memorizzerà il primo pixel nero poi metterà il carattere speciale e in seguito memorizzerà il numero 100. Così invece di occupare cento locazioni la prima riga ne occuperà solo 3. Il carattere speciale è definito diversamente da ogni implementazione dell'algoritmo, e serve a distinguere un elemento normale da uno compresso.
Questo algoritmo funziona bene in presenza di immagini con pochi colori molto uniformi, ovvero in serie di dati che abbiano molte ripetizioni al loro interno.
(http://it.wikipedia.org/wiki/Run-length_encoding)
[2]
DICOM Part 10 Data Loading
Quando si caricano dati DICOM, ci si riferisce alla directory dell'ultima operazione DICOM. Se esiste un file DICOMDIR nella directory, solo gli studi registrati nel DICOMDIR sono presentati per essere caricati. Se non esiste il file DICOMDIR, tutti i file nella directory sono scandagliati e tutti gli studi DICOM validi sono listati.
(http://www.pmod.com/technologies/doc/pbas/689.htm)
[3]
DICOMDIR
Il formato file DICOMDIR è stato difinito per accedere per accedere ai DICOM part 10 files. Per esempio, i CD DICOM compliant contengono in DICOMDIR al livello root tutte le descrizioni e le informazioni di accesso per tutti gli studi nel CD.
(http://www.pmod.com/technologies/doc/pbas/1990.htm)
[4]
Un Presentation State è un DICOM SOP indipendente che contiene informazioni su come una particolare immagine deve essere mostrata. Il Presentation State può contenere informazioni su: tipo, posizione, valori sulla finestre, valori di zoom, valori sullo scrolling (panning), rotazione o altri elementi per la vusualizzazione che sono definiti nello standard DICOM. Bisogna dire che il Presentation States non contiene informaizoni su i Pixel Data. Il vantaggio dell'uso del presentation states è che è sempre possibile tornare indietro all'immagine origianel in quanto i pixel non sono modificati ma solo come questa è mostrata. Il Presentation states può essere inviato al PACS (se il PACS sipporta le classi Presentations state SOP) e ritrovata quando richiesta.
(http://www.medicalconnections.co.uk/wiki/Presentation_states)
[5]
DICOM SR
Formato per i referti.
Command line XML toolkit
XMLStarlet is a set of command line utilities (tools) which can be used to transform, query, validate, and edit XML documents and files using simple set of shell commands in similar way it is done for plain text files using UNIX grep, sed, awk, diff, patch, join, etc commands.
This set of command line utilities can be used by those who deal with many XML documents on UNIX shell command prompt as well as for automated XML processing with shell scripts.
The toolkit's feature set includes options to:
Check or validate XML files (simple well-formedness check, DTD, XSD, RelaxNG)
Calculate values of XPath expressions on XML files (such as running sums, etc)
Search XML files for matches to given XPath expressions
Apply XSLT stylesheets to XML documents (including EXSLT support, and passing parameters to stylesheets)
Query XML documents (ex. query for value of some elements of attributes, sorting, etc)
Modify or edit XML documents (ex. delete some elements)
Format or "beautify" XML documents (as changing indentation, etc)
Fetch XML documents using http:// or ftp:// URLs
Browse tree structure of XML documents (in similar way to 'ls' command for directories)
Include one XML document into another using XInclude
XML c14n canonicalization
Escape/unescape special XML characters in input text
Print directory as XML document
Convert XML into PYX format (based on ESIS - ISO 8879), and vice versa
XMLBeans è una libreria scritta dalla Apache che permette di manipolare il contenuto di un file XML fornendo una visione a oggetti dei dati e implementando tutte le funzionalità necessarie allo sviluppatore per gestire in modo automatico le operazioni di lettura, scrittura e validazione di un file XML. La versione che utilizzeremo nel nostro esempio è la 2.3.0.
Mediante XMLBeans è possibile generare delle classi java che permettono di leggere, scrivere o validare un file xml. Per generare le classi occorre preparare un file xsd nel quale sono definite tutte le regole a cui i file XML devono essere conformi.
Per utilizzare XmlBeans bisogna settare le seguenti variabili di ambiente:
* XMLBEANS_HOME contenente il path della root di XMLBeans;
* JAVA_HOME contenente il path della root del JDK;
* Aggiungere al CLASSPATH la libreria %XMLBEANS_HOME%\lib\xbean.jar
è necessario inoltre aggiungere alla variabile di ambiente PATH la cartella bin del JDK e la directory bin di XMLBeans.
Come esempio creeremo le classi java che serviranno per leggere e scrivere file XML del tipo:
Listato 1. Esempio di un XML
<iscritti>
<iscritto matricola="..." nome="..." cognome="...">
<esame voto="..">..</esame>
<esame voto="..">..</esame>
<esame voto="..">..</esame>
</iscritto>
<iscritto matricola="..." nome="..." cognome="...">
<esame voto="..">..</esame>
</iscritto>
<iscritto matricola="..." nome="..." cognome="...">
</iscritto>
...
</iscritti>
Il tag principale è "iscritti", che può contenere da zero a n tag "iscritto". Ciascun iscritto ha tre attributi (matricola, nome e cognome) e può contenere zero o n tag esame. Ciascun esame ha un attributo (voto) e, il suo valore, rappresenta l'esame sostenuto dallo studente.
Prima di tutto bisogna scrivere il file xsd nel quale viene definita tale struttura. Scrivere a mano un file xsd non è semplicissimo, in aiuto ci viene XMLSpy che ci permette di scriverlo sfruttando le classiche tecniche del drag & drop.
(http://java.html.it/articoli/leggi/2367/xmlbeans/)
Listato 2. Esempio di un file XSD
<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2007 rel. 3 sp1 by Luca -->
<xs:schema xmlns:xs=http://www.w3.org/2001/XMLSchema xmlns:sf=http://www.sportfantasy.org
targetNamespace="http://www.sportfantasy.org" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="iscritto">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="esame">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="voto">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:maxInclusive value="30"/>
<xs:minInclusive value="18"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="matricola" type="xs:string" use="required"/>
<xs:attribute name="nome" type="xs:string" use="required"/>
<xs:attribute name="cognome" type="xs:string" use="required"/>
</xs:complexType>
<xs:element name="iscritti">
<xs:annotation>
<xs:documentation>Comment describing your root element</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="iscritto" type="sf:iscritto"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Per generare le classi java che permettono di gestire i file XML conformi alla seguente struttura apriamo una shell, portiamoci nella directory nella quale è contenuto il file xsd (iscritti.xsd) appena creato e lanciamo il seguente comando:
scomp iscritti.xsd –out iscritti.jar
Con questo comando viene creata la libreria (iscritti.jar) che contiene le classi java che ci permettono di scrivere e leggere i file XML compatibili con l'xsd. Le classi hanno come package uguale al namespace URI dell'xsd. Nel nostro caso org.sportfantasy.
La classe principale è IscrittiDocument che incapsula l'intero documento XML. Per ciascun tipo complesso definito nell'xsd è stata generata un'interfaccia e una classe che la implementa. Tutte le classi hanno a disposizione i metodi getter e setter rispettivamente per leggere e scrivere le proprietà dell'oggetto. Ad esempio la classe Iscritto avrà come metodo getNome() e setNome(). Naturalmente l'attrbuto nome della classe Iscritto è di tipo stringa così come definito nell'xsd. Poich矩l tag iscritti può contenere n tag iscritto, la classe Iscritti avrà a disposizione un metodo che permette di aggiungere un Iscritto (addNewIscritto()). Allo stesso modo la classe Iscritto avrà a disposizione un metodo che permette di aggiungere un Esame (addNewEsame()).
Notiamo che ogni interfaccia che rappresenta un elemento dell'XML schema, contiene un'inner class "Factory", creata secondo il pattern abstract Factory, che permette di creare un oggetto java che incapsula l'elemento. Ad esempio il comando IscrittiDocument.Factory.newInstance() ci permette di ottenere un'istanza del documento.
Vediamo come utilizzare la libreria per scrivere un file xml conforme alla struttura definita.
Listato 3. Utilizzo della libreria per scrivere un file xml
import java.io.File;
import java.io.IOException;
import org.apache.xmlbeans.XmlOptions;
import org.sportfantasy.IscrittiDocument;
import org.sportfantasy.Iscritto;
import org.sportfantasy.IscrittiDocument.Iscritti;
import org.sportfantasy.Iscritto.Esame;
public class Scrittura
{
public static void main(String[] args) throws IOException
{
//doc è un'istanza del documento xml
IscrittiDocument doc = IscrittiDocument.Factory.newInstance();
//aggiungiamo un tag iscritti al documento
Iscritti studenti = doc.addNewIscritti();
//aggiungiamo uno studente e settiamo i sui attributi
Iscritto studente1 = studenti.addNewIscritto();
studente1.setMatricola("544-843");
studente1.setNome("Pippo");
studente1.setCognome("Baudo");
//aggiungiamo un esame allo studente e settiamo gli attributi
Esame esame1 = studente1.addNewEsame();
esame1.setVoto(18);
esame1.setStringValue("Programmazione");
//aggiungiamo un altro esame allo studente e settiamo gli attributi
Esame esame2 = studente1.addNewEsame();
esame2.setVoto(30);
esame2.setStringValue("Tecnologie WEB");
//aggiungiamo un altro studente e settiamo i sui attributi
Iscritto studente2 = studenti.addNewIscritto();
studente2.setMatricola("503-1092");
studente2.setNome("Mike");
studente2.setCognome("Buongiorno");
//aggiungiamo un esame allo studente e settiamo gli attributi
Esame esame3 = studente2.addNewEsame();
esame3.setVoto(30);
esame3.setStringValue("Analisi 2");
//settiamo le opzioni utilizzate per la stampa o la scrittura
XmlOptions opts = new XmlOptions();
//questa opzione permette di indentare il codice xml
opts.setSavePrettyPrint();
System.out.println(doc.xmlText(opts));
//salviamo il file sul disco
doc.save(new File ("C:/test.xml"), opts);
}
}
Vediamo, infine, come utilizzare la libreria per la lettura di un file xml conforme alla struttura definita.
Listato 4. Utilizzo della libreria per leggere un file xml
import java.io.File;
import org.sportfantasy.IscrittiDocument;
import org.sportfantasy.Iscritto;
import org.sportfantasy.IscrittiDocument.Iscritti;
import org.sportfantasy.Iscritto.Esame;
public class Lettura
{
public static void main(String[] args) throws Exception
{
//caricamento del file xml
IscrittiDocument doc = IscrittiDocument.Factory.parse(new File ("C:/test.xml"));
//root è un'istanza del documento xml
Iscritti root = doc.getIscritti();
//studenti è un array di oggetti Iscritto
Iscritto[] studenti = root.getIscrittoArray();
System.out.println("STUDENTI ISCRITTI: " + studenti.length);
for (int i=0; i<studenti.length; i++)
{
//lettura dell'iesimo iscritto
Iscritto studente = root.getIscrittoArray(i);
System.out.println(studente.getNome() + " " + studente.getCognome() + " " + studente.getMatricola());
for (int j=0; j<studente.getEsameArray().length; j++)
{
//lettura del j'esimo esame
Esame esame = studente.getEsameArray(j);
System.out.println(esame.getStringValue()+ " " + esame.getVoto());
}
System.out.println();
}
}
}
Architettura di J2EE L' architettura proposta dalla piattaforma J2EE divide le applicazioni enterprise in tre strati applicativi fondamentali: componenti, contenitori e connettori. Il modello di programmazione prevede lo sviluppo di soluzioni utilizzando componenti a supporto delle quali fornisce quattro tecnologie fondamentali:
Enterprise
Java Beans;
Servelet ;
Java Server Pages ;
Applet.
La
prima delle quattro che per semplicità denoteremo con EJB fornisce
supporto per la creazione di componenti server-side che possono
essere generate indipendentemente da uno specifico database, da uno
specifico transaction server o dalla piattaforma su cui gireranno. La
seconda, servlet, consente la costruzione di servizi web altamente
performanti ed in grado di funzionare sulla maggior parte dei web
server ad oggi sul mercato. La terza, JavaServer Pages o JSP,
permette di costruire pagine web dai contenuti dinamici utilizzando
tutta la potenza del linguaggio java. Le applet, anche se sono
componenti client-side rappresentano comunque tecnologie appartenenti
allo strato delle componenti.
Il secondo strato è rappresentato
dai contenitori ovvero supporti tecnologici alle tecnologie
appartenenti al primo strato logico della architettura. La
possibilità di costruire contenitori rappresenta la caratteristica
fondamentale del sistema in quanto fornisce ambienti scalari con alte
performance.
Infine i connettori consentono alle soluzioni basate
sulla tecnologia J2EE di preservare e proteggere investimenti in
tecnologie già esistenti fornendo uno strato di connessione verso
applicazioni-server o middleware di varia natura: dai database
relazionali con JDBC fino ai server LDAP con JNDI.
J2EE
Application Model
Date le caratteristiche della piattaforma, l'
aspetto più interessante è legato a quello che le applicazioni non
devono fare; la complessità intrinseca delle applicazioni enterprise
quali gestione delle transazioni, ciclo di vita delle componenti,
pooling delle risorse viene inglobata all' interno della piattaforma
che provvede autonomamente alle componenti ed al loro supporto.
Programmatori e analisti sono quindi liberi di concentrarsi su
aspetti specifici della applicazione come presentazione o logiche di
business non dovendosi occupare di aspetti la cui complessità non è
irrilevante e, in ambito progettuale ha un impatto notevolissimo su
costi e tempi di sviluppo.
A supporto di questo, l' Application
Model descrive la stratificazione orizzontale tipica di una
applicazione J2EE. Tale stratificazione identifica quattro settori
principali : Client Tier, Web Tier, Business-Tier, EIS-Tier.
Client
Tier
Appartengono allo strato client le applicazioni che
forniscono all' utente una interfaccia semplificata verso il mondo
enterprise e rappresentano quindi la percezione che l' utente ha
della applicazione J2EE. Tali applicazioni si suddividono in due
classi di appartenenza : le applicazioni web-based e le applicazioni
non-web-based.
Le prime sono quelle applicazioni che utilizzano
il browser come strato di supporto alla interfaccia verso l' utente
ed i cui contenuti vengono generati dinamicamente da Servlet o Java
Server Pages o staticamente in HTML. Le seconde (non-web-based) sono
invece tutte quelle basate su applicazioni stand-alone che sfruttano
lo strato di rete disponibile sul client per interfacciarsi
direttamente con la applicazione J2EE senza passare per il Web-Tier.
Web
Tier
Le componenti web-tier di J2EE sono rappresentate da pagine
JSP, server-side applet e Servlet. Le pagine HTML che invocano
Servlet o JSP secondo lo standard J2EE non sono considerate
web-components, ed il motivo è il seguente : come illustrato nei
paragrafi precedenti si considerano componenti, oggetti caricabili e
gestibili all'interno di un contenitore in grado di sfruttarne i
servizi messi a disposizione. Nel nostro caso, Servlet e JSP hanno il
loro ambiente runtime all'interno del "Servlet-Container"
che provvede al loro ciclo di vita, nonché alla fornitura di servizi
quali client-request e client-response ovvero come un client
appartenente allo strato client-tier rappresenta la percezione che
l'utente ha della applicazione J2EE, il contenitore rappresenta la
percezione che una componente al suo interno ha della interazione
verso l'esterno.
La piattaforma J2EE prevede quattro tipi di
applicazioni web : "basic HTML", "HTML with base JSP
and Servlet" " , Servlet and JSP with JavaBeans
components", "High Structured Application con componenti
modulari", "Servlet ed Enterprise Beans" Di queste, le
prime tre sono dette "applicazioni web-centric" quelle
appartenenti al quarto tipo sono dette " applicazioni EJB
Centric" La scelta di un tipo di applicazione piuttosto che di
un altro dipende ovviamente da vari fattori tra cui:
Complessità
del problema;
Risorse del Team di sviluppo;
Longevità della
applicazione;
Dinamismo dei contenuti da gestire e proporre.
Business
Tier
Nell' ambito di una applicazione enterprise, è questo lo
strato che fornisce servizi specifici: gestione delle transazioni,
controllo della concorrenza, gestione della sicurezza, ed implementa
inoltre logiche specifiche circoscritte all' ambito applicativo ed
alla manipolazione dei dati. Mediante un approccio di tipo Object
Oriented è possibile decomporre tali logiche o logiche di business
in un insieme di componenti ed elementi chiamati " business
object".
La tecnologia fornita da Sun per implementare i "
business object" è quella che in precedenza abbiamo indicato
come EJBs (Enterprise Java Beans). Tali componenti si occupano di:
Ricevere dati da un client, processare tali dati (se necessario),
inviare i dati allo strato EIS per la loro memorizzazione su base
dati; (Viceversa) Acquisire dati da un database appartenente allo
strato EIS, processare tali dati (se necessario), inviare tali dati
al programma client che ne abbia fatto richiesta.
Esistono due
tipi principali di EJBs : entity beans e session beans. Per session
bean si intende un oggetto di business che rappresenta una risorsa "
privata" rispetto al client che lo ha creato. Un entity bean al
contrario rappresenta in modo univoco un dato esistente all'interno
dello strato EIS ed ha quindi una sua precisa identità rappresentata
da una chiave primaria.
Oltre alle componenti, la architettura
EJB definisce altre 3 entità fondamentali: servers, containers e
client. Un Enterprise Bean vive all'interno del container che
provvede al ciclo vitale della componente e ad una varietà di latri
servizi quali gestione della concorrenza e scalabilità. L' EJB
Container è a sua volta parte di un EJB server che fornisce tutti i
servizi di naming e di directory (tali problematiche verranno
affrontate negli articoli successivi).
Quando un client invoca
una operazione su un EJB, la chiamata viene intergettata dal
container. Questa intercessione del container tra client ed EJB a
livello di "chiamata a metodo" consente al container la
gestione di quei servizi di cui si è parlato all'inizio del
paragrafo oppure della propagazione della chiamata ad altre
componenti (Load Balancing) o ad altri container (Scalabilità) su
altri server sparsi per la rete su differenti macchine.
Nella
implementazione di una architettura enterprise, oltre a decidere che
tipo di enterprise beans utilizzare, un programmatore deve effettuare
altre scelte strategiche nella definizione del modello a componenti :
Che tipo di oggetto debba rappresentare un Enterprise Bean;
Che
ruolo tale oggetto deve avere all' interno di un gruppo di componenti
che collaborino tra di loro.
Dal momento che gli enterprise beans
sono oggetti che necessitano di abbondanti risorse di sistema e di
banda di rete, non sempre è soluzione ottima modellare tutti i
business object come EJBs. In generale una soluzione consigliabile è
quella di adottare tale modello solo per quelle componenti che
necessitino un accesso diretto da parte di un client.
EIS-Tier
Le applicazioni enterprise implicano per definizione l'accesso ad
altre applicazioni, dati o servizi sparsi all' interno delle
infrastrutture informatiche del fornitore di servizi. Le informazioni
gestite ed i dati contenuti all'interno di tali infrastrutture
rappresentano la " ricchezza" del fornitore, e come tale
vanno trattati con estrema cura garantendone la integrità.
Al
modello bidimensionale delle vecchie forme di business legato ai
sistemi informativi (figura 11-9) è stato oggi sostituito da un
nuovo modello (e-business) che introduce una terza dimensione che
rappresenta la necessità da parte del fornitore di garantire accesso
ai dati contenuti nella infrastruttura enterprise via web a: partner
commerciali, consumatori, impiegati e altri sistemi informativi.
Gli
scenari di riferimento sono quindi svariati e comprendono vari
modelli di configurazione che le architetture enterprise vanno ad
assumere per soddisfare le necessità della new-economy. Un modello
classico è quello rappresentato da sistemi di commercio elettronico.
Nei negozi virtuali o E-Store l'utente web interagisce tramite
browser con i cataloghi on-line del fornitore, seleziona i prodotti,
inserisce i prodotti selezionati nel carrello virtuale, avvia una
transazione di pagamento con protocolli sicuri.
Le
API di J2EE
Le API di J2EE forniscono supporto al programmatore
per lavorare con le più comuni tecnologie utilizzate nell'ambito
della programmazione distribuita e dei servizi di interconnessione
via rete. I prossimi paragrafi forniranno una breve introduzione alle
API componenti lo strato tecnologico fornito con la piattaforma
definendo volta per volta la filosofia alla base di ognuna di esse e
tralasciando le API relative a Servlet, EJBs e JavaServer Pages già
introdotte nei paragrafi precedenti.
JDBC
: Java DataBase Connectivity
Rappresentano le API di J2EE per
poter lavorare con database relazionali. Esse consentono al
programmatore di inviare query ad un database relazionale, di
effettuare dolete o update dei dati all'interno di tabelle, di
lanciare stored-procedure o di ottenere meta-informazioni
relativamente al database o le entità che lo compongono.
RMI
: Remote Method Invocation
Remote Method Invocation fornisce il
supporto per sviluppare applicazioni java in grado di invocare metodi
di oggetti distribuiti su virtual-machine differenti sparse per la
rete. Grazie a questa tecnologia è possibile realizzare architetture
distribuite in cui un client invoca metodi di oggetti residenti su un
server che a sua volta può essere client nei confronti di un altro
server.
JNDI
Java Naming and Directory Interface è quell'insieme di API che
forniscono l'accesso a servizi generici di Naming o Directory
attraverso la rete. Consentono, alla applicazione che ne abbia
bisogno, di ottenere oggetti o dati tramite il loro nome o di
ricercare oggetti o dati mediante l'uso di attributi a loro
associati.
JMS
Java Message Service o Enterprise Messaging rappresentano le API
forniscono supporto alle applicazioni enterprise nella gestione
asincrona della comunicazione verso servizi di " messaging"
o nella creazione di nuovi MOM (Message Oriented Middleware).
Nonostante JMS non sia così largamente diffuso come le altre
tecnologie, svolge un ruolo importantissimo nell'ambito di sistemi
enterprise.
Per meglio comprenderne il motivo è necessario
comprendere il significato della parola " messaggio" che in
ambito JMS rappresenta tutto l'insieme di messaggi asincroni
utilizzati dalle applicazioni enterprise, non dagli utenti umani,
contenenti dati relativi a richieste, report o eventi che si
verificano all' interno del sistema fornendo informazioni vitali per
il coordinamento delle attività tra i processi. Essi contengono
informazioni impacchettate secondo specifici formati relativi a
particolari "eventi di business" .
Grazie a JMS è
possibile scrivere applicazioni di business " message-based"
altamente portabili fornendo una alternativa a RMI che risulta
necessaria in determinati ambiti applicativi. Nella figura 11-14 è
schematizzata una soluzione tipo di applicazioni basate su messaggi.
Una applicazione di " Home Banking" deve interfacciarsi con
il sistema di messagistica bancaria ed interbancaria da cui trarre
tutte le informazioni relative alla gestione economica dell'utente.
Nel modello proposto da J2EE l'accesso alle informazioni
contenute all'interno di questo strato è possibile tramite oggetti
chiamati " connettori"che rappresentano una architettura
standard per integrare applicazioni e componenti enterprise
eterogenee con sistemi informativi enterprise anche loro eterogenei.
I connettori sono messi a disposizione della applicazione
enterprise grazie al server J2EE che li contiene sotto forma di
servizi di varia natura (es. Pool di connessioni) e che tramite
questi collabora con i sistemi informativi appartenenti allo strato
EIS in modo da rendere ogni meccanismo a livello di sistema
completamente trasparente alle applicazioni enterprise. Lo stato
attuale dell' arte prevede che la piattaforma J2EE consenta pieno
supporto per la connettività verso database relazionali tramite le
API JDBC, le prossime versioni della architettura J2EE prevedono
invece pieno supporto transazionale verso i più disparati sistemi
enterprise oltre che a database relazionali.
Architettura
del Web Tier
Introduzione
Chi ha potuto accedere ad internet
a partire dagli inizi degli anni 90, quando ancora la diffusione
della tecnologia non aveva raggiunto la massa ed i costi erano
eccessivi (ricordo che nel 1991 pagai un modem interno usato da 9600
bps la cifra incredibile di 200.000 lire), ha assistito alla
incredibile evoluzione che ci ha portato oggi ad una diversa
concezione del computer.
A partire dai primi siti internet dai
contenuti statici, siamo oggi in grado di poter effettuare qualsiasi
operazione tramite Web da remoto. Questa enorme crescita, come una
vera rivoluzione, ha voluto le sua vittime. Nel corso degli anni sono
nate e poi completamente scomparse un gran numero di tecnologie a
supporto di un sistema in continua evoluzione.
Servlet e
JavaServer Pages rappresentano oggi lo stato dell'arte delle
tecnologie web. Raccogliendo la pesante eredità lasciata dai suoi
predecessori, la soluzione proposta da SUN rappresenta quanto di più
potente e flessibile possa essere utilizzato per sviluppare
applicazioni web.
L'architettura
del "Web Tier"
Prima di affrontare il tema dello
sviluppo di applicazioni web con Servlet e JavaServer Pages è
importante fissare alcuni concetti. Il web-server gioca un ruolo
fondamentale all'interno di questo strato. In ascolto su un server,
riceve richieste da parte del browser (client), le processa, quindi
restituisce al client una entità o un eventuale codice di errore
come prodotto della richiesta.
Le entità prodotte da un
web-server possono essere entità statiche o entità dinamiche. Una
entità statica è ad esempio un file html residente sul file-system
del server. Rispetto alle entità statiche, unico compito del web
server è quello di recuperare la risorsa dal file-system ed inviarla
al browser che si occuperà della visualizzazione dei contenuti.
Quello che più ci interessa sono invece le entità dinamiche,
ossia entità prodotte dalla esecuzione di applicazioni eseguite dal
web-server su richiesta del client.
Il modello proposto nella
immagine 1 ora si complica in quanto viene introdotto un nuovo grado
di complessità (Figura 2-12) nella architettura del sistema che,
oltre a fornire accesso a risorse statiche dovrà fornire un modo per
accedere a contenuti e dati memorizzati su una Base Dati, dati con i
quali un utente internet potrà interagire da remoto.
Inviare
dati
Mediante form HTML è possibile inviare dati ad un
web-server. Tipicamente l'utente riempie alcuni campi il cui
contenuto, una volta premuto il pulsante " submit" viene
inviato al server con il messaggio di richiesta. La modalità con cui
questi dati vengono inviati dipende dal metodo specificato nella
richiesta. Utilizzando il metodo GET, i dati vengono appesi alla
request-URI nella forma di coppie chiave=valore separati tra di loro
dal carattere "?" . La stringa seguente è un esempio di
campo request-URI per una richiesta di tipo GET.
http://www.java-net.tv/servelt/Hello?nome=Massimo&cognome=Rossi
"http://www.java-net.tv" rappresenta l'indirizzo del
web-server a cui inviare la richiesta. I campi "/servlet/Hello"
rappresenta la locazione della applicazione web da eseguire. Il
carattere "?" separa l'indirizzo dai dati e il carattere
"&" separa ogni coppia chiave=valore.
Questo metodo
utilizzato per default dai browser a meno di specifiche differenti,
viene utilizzato nei casi in cui si richieda al server il recupero di
informazioni mediante query su un database.
Il metodo POST pur
producendo gli stessi effetti del precedente, utilizza una modalità
di trasmissione dei dati differente impacchettando i contenuti dei
campi di un form all'interno di un message-header. Rispetto al
precedente, il metodo POST consente di inviare una quantità maggiore
di dati ed è quindi utilizzato quando è necessario inviare al
server nuovi dati affinché possano essere memorizzati all'interno
della Base Dati.
Sviluppare applicazioni web
A meno di
qualche eccezione una applicazione web è paragonabile ad una
qualsiasi applicazione con la differenza che deve essere accessibile
al web-server che fornirà l'ambiente di runtime per l'esecuzione.
Affinché ciò sia possibile è necessario che esista un modo
affinché il web-server possa trasmettergli i dati inviati dal
client, che esista un modo univoco per l'accesso alle funzioni
fornite dalla applicazione (entry-point), che l'applicazione sia in
grado di restituire al web-server i dati prodotti in formato HTML da
inviare al client nel messaggio di risposta.
Esistono molte
tecnologie per scrivere applicazioni web che vanno dalla più comune
"CGI" a soluzioni proprietarie come ISAPI di Microsoft o
NSAPI della Netscape.
Common
Gateway Interface
CGI è sicuramente la più comune e datata tra
le tecnologie server-side per lo sviluppo di applicazioni web. Scopo
principale di un CGI è quello di fornire funzioni di "gateway"
tra il web-server e la base dati del sistema.
I CGI possono
essere scritti praticamente con tutti i linguaggi di programmazione.
Questa caratteristica classifica i CGI in due categorie: CGI
sviluppati mediante linguaggi script e CGI sviluppati con linguaggi
compilati. I primi, per i quali viene generalmente utilizzato il
linguaggio PERL, sono semplici da implementare, ma hanno lo
svantaggio di essere molto lenti e per essere eseguiti richiedono l'
intervento di un traduttore che trasformi le chiamate al linguaggio
script in chiamate di sistema. I secondi a differenza Dei primi sono
molto veloci, ma risultano difficili da programmare (generalmente
sono scritti mediante linguaggio C).
Il più grande svantaggio
nell' uso dei CGI sta nella scarsa scalabilità della tecnologia
infatti, ogni volta che il web-server riceve una richiesta deve
creare una nuova istanza del CGI. Il dover stanziare un processo per
ogni richiesta ha come conseguenza enormi carichi in fatto di risorse
macchina e tempi di esecuzione. A meno di non utilizzare strumenti di
altro tipo è inoltre impossibile riuscire ad ottimizzare gli accessi
al database. Ogni istanza del CGI sarà difatti costretta ad aprire e
chiudere una propria connessione verso il DBMS. Questi problemi sono
stati affrontati ed in parte risolti dai Fast-CGI grazie ai quali è
possibile condividere una stessa istanza tra più richieste http.
ISAPI
ed NSAPI
Per far fronte ai limiti tecnologici imposti dai CGI,
Microsoft e Netscape hanno sviluppato API proprietarie mediante le
quali creare librerie ed applicazioni che possono essere caricate dal
web-server al suo avvio ed utilizzate come proprie estensioni.
L'insuccesso di queste tecnologie è stato però segnato proprio
dalla loro natura di tecnologie proprietarie e quindi non portabili
tra le varie piattaforme sul mercato.
Essendo utilizzate come
moduli del web-server era inoltre caso frequente che un loro accesso
errato alla memoria causasse il "crash" dell'intero
web-server provocando enormi danni al sistema che doveva ogni volta
essere riavviato.
ASP
– Active Server Pages
Active Server Pages è stata l'ultima
tecnologia web rilasciata da Microsoft. Una applicazione ASP è
tipicamente un misto tra HTML e linguaggi script come VBScript o
JavaScript mediante i quali si può accedere ad oggetti del server.
Una pagina ASP, a differenza di ISAPI, non viene eseguita come
estensione del web-server, ma viene compilata alla prima chiamata, ed
il codice compilato può quindi essere utilizzato ad ogni richiesta
HTTP.
Nonostante sia oggi largamente diffusa, ASP come ISAPI
rimane una tecnologia proprietaria e quindi in grado di funzionare
solamente su piattaforma Microsoft, ma il reale svantaggio di ASP è
però legato alla sua natura di mix tra linguaggi script ed HTML.
Questa sua caratteristica ha come effetto secondario quello di
riunire in un unico " contenitore" sia le logiche
applicative che le logiche di presentazione rendendo estremamente
complicate le normali operazioni di manutenzione delle pagine.
Java
Servlet e JavaServer Pages
Sun cerca di risolvere i problemi
legati alle varie tecnologie illustrate, mettendo a disposizione del
programmatore due tecnologie che raccogliendo l'eredità dei
predecessori, ne abbattono i limiti mantenendo e migliorando gli
aspetti positivi di ognuna. In aggiunta Servlet e JavaServer Pages
ereditano tutte quelle caratteristiche che rendono le applicazioni
Java potenti, flessibili e semplici da mantenere: portabilità del
codice, paradigma object oriented.
Rispetto ai CGI, Servlet
forniscono un ambiente ideale per quelle applicazioni per cui sia
richiesta una massiccia scalabilità e di conseguenza
l'ottimizzazione degli accessi alle basi dati di sistema.
Rispetto
ad ISAPI ed NSAPI, pur rappresentando una estensione al web server,
mediante il meccanismo delle eccezioni risolvono a priori tutti gli
errori che potrebbero causare la terminazione prematura del sistema.
Rispetto ad ASP, Servlet e JavaServer Pages separano
completamente le logiche di business dalle logiche di presentazione
dotando il programmatore di un ambiente semplice da modificare o
mantenere.
http://www.freeonline.org/guide/javalibro_dtml
Dispatcher
In un sistema ad eventi il ruolo fondamentale è svolto dal dispatcher il quale riceve i messaggi da una moltitudine di produttori e li re-invia a più destinatari.
I compiti principali che deve svolgere il dispatcher sono i seguenti:
Permettere ai sistemi della struttura di registrarsi al sistema e di consegnare i proprio certificati di autenticazione.
Permettere agli amministratori di gestire i tipi di messaggi che possono transitare e gli xsd di questi messaggi.
Controllo dell'identità dei mittenti e dei destinatari, per far ciò useremo un sistema di criptografia a doppia chiave ovvero ci deve essere uno scambio reciproco di certificati tra ogni sistema periferico e il dispatcher, in questo modo quando il dispatcher deve inviare un messaggio andrà a criptare il messaggio prima con la sua chiave privata e poi con la chiave pubblica del destinatario, viceversa quando un sistema deve inviare un messaggio al dispatcher prima cripterà il body del messaggio con la sua chiave privata e poi tutto il messaggio con la chiave pubblica del dispatcher, in questo modo il dispatcher all'arrivo del messaggio userà la sua chiave privata per interpretare quel messaggio quindi prelevare l'header e da questo risalire al mittente e quindi alla sua chiave pubblica precedentemente rilasciata al dispatcher.
Verifica del formato del corpo del messaggio, dopo averne ricavato il tipo, attraverso il confronto con l'XSD per quel tipo di messaggio.
Verifica se il mittente poteva inviare quel tipo di messaggi.
Invio del messaggio di ACK (con specificato il Message Control ID del messaggio inviato) per notificare al mittente l'esito della consegna e se tutte le verifiche sono andate a buon fine.
Qualora le verifiche sono andate a buon fine deve inoltrare il messaggio all'apposita coda per l'invio asincrono ai sistemi interessati a quel messaggio. Qui è bene soffermarci un attimo. Alcuni messaggi, come ad esempio le modifiche dell'anagrafe andranno inoltrati a più sistemi, mentre alcuni messaggi come ad esempio la richiesta di una specifica informazione al laboratorio di analisi andrà inoltrata solo a questo. Per cui dalle informazioni ricavate dal testo del messaggio andrà inviato lo stesso ad un diverso dominio di invio: Publisher/Subscriber oppure Point-to-Point. Nel primo caso i sistemi che sono interessati ad un determinato tipo di messaggio si iscrivono ad un gruppo e poi quel messaggio sarà inoltrato a tutti gli iscritti. Nel secondo caso invece il messaggio sarà inviato solo al destinatario specificato nel messaggio stesso (segmento MSH messaggio HL7 - Sending Application – Receiving Application).
Gestione dei messaggi di ACK. Dai sistemi a cui è stato inviato il messaggio da parte del Dispatcher ci si attende un messaggio di ACK (con specificato il Message Control ID del messaggio inviato), e solo quando questo è stato ricevuto si potrà continuare con l'invio di altri messaggi a quel sistema.
Registrazione dei mittenti e del tipo di messaggio inviato da questi e dei destinatari e del tipo di messaggio inviato a questi nel database di Log.
MSH attributes – HL7 v 2.4
SEQ |
LEN |
DT |
OPT |
RP/# |
TBL# |
ITEM # |
ELEMENT NAME |
1 |
1 |
ST |
R |
|
|
00001 |
Field Separator |
2 |
4 |
ST |
R |
|
|
00002 |
Encoding Characters |
3 |
180 |
HD |
O |
|
|
00003 |
Sending Application |
4 |
180 |
HD |
O |
|
|
00004 |
Sending Facility |
5 |
180 |
HD |
O |
|
|
00005 |
Receiving Application |
6 |
180 |
HD |
O |
|
|
00006 |
Receiving Facility |
7 |
26 |
TS |
O |
|
|
00007 |
Date/Time Of Message |
8 |
40 |
ST |
O |
|
|
00008 |
Security |
9 |
7 |
CM |
R |
|
|
00009 |
Message Type |
10 |
20 |
ST |
R |
|
|
00010 |
Message Control ID |
11 |
3 |
PT |
R |
|
|
00011 |
Processing ID |
12 |
8 |
ID |
R |
|
0104 |
00012 |
Version ID |
13 |
15 |
NM |
O |
|
|
00013 |
Sequence Number |
14 |
180 |
ST |
O |
|
|
00014 |
Continuation Pointer |
15 |
2 |
ID |
O |
|
0155 |
00015 |
Accept Acknowledgment Type |
16 |
2 |
ID |
O |
|
0155 |
00016 |
Application Acknowledgment Type |
17 |
2 |
ID |
O |
|
|
00017 |
Country Code |
18 |
6 |
ID |
O |
Y/3 |
0211 |
00692 |
Character Set |
19 |
60 |
CE |
O |
|
|
00693 |
Principal Language Of Message |
Nella tabella sopra sono riportati tutti gli attributi del segmento MSH dei vari messaggi HL7. Questo segmento deve essere inserito nell'Header del messaggio in quanto contiene tutti i dati necessari per il routing del messaggio stesso.
Codice JAVA
Servlet1.java
import classi_varie.fil_writ;
import classi_varie.db1;
import java.sql.SQLException;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.net.*;
/**
*
* @author davide
*/
public class Servlet1 extends HttpServlet {
private static String message = "Error during Servlet processing";
public void doPost(HttpServletRequest req, HttpServletResponse resp) {
try {
int len = req.getContentLength();
byte[] input = new byte[len];
ServletInputStream sin = req.getInputStream();
int c, count = 0;
while ((c = sin.read(input, count, input.length-count)) != -1) {
count +=c;
}
sin.close();
String inString = new String(input);
int index = inString.indexOf("=");
if (index == -1) {
resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
resp.getWriter().print(message);
resp.getWriter().close();
return;
}
String value = inString.substring(index + 1);
//Decripta inString
//decode application/x-www-form-urlencoded string
String decodedString = URLDecoder.decode(value, "UTF-8");
fil_writ.addLineToFile("/home/davide/Documenti/progetto_s_e/sorgenti/elenco.txt", decodedString);
fil_writ.create_xml(decodedString, "/home/davide/Documenti/progetto_s_e/sorgenti/temporaney.xml");
String tipo=null;
//estrai tipo da inString;
int beg_seg = decodedString.indexOf("EVN");
String tipo1=value.substring(beg_seg+8);
int end_seg=tipo1.lastIndexOf("EVN");
tipo=tipo1.substring(0, end_seg-6);
//verifica se estra tipo
fil_writ.addLineToFile("/home/davide/Documenti/progetto_s_e/sorgenti/messaggi_ADT.txt", tipo);
String[] Lista_destinatari=null;
int errori0=0;
try {
Lista_destinatari=db1.main(tipo);//"root", "260885", tipo);
} catch (ClassNotFoundException ex) {
//Logger.getLogger(Servlet1.class.getName()).log(Level.SEVERE, null, ex);
errori0=1;
} catch (SQLException ex) {
//Logger.getLogger(Servlet1.class.getName()).log(Level.SEVERE, null, ex);
errori0=1;
}
int errori1=0;
//test per vedere se dal database scappa qualcosa - OK
/*int indice21=Lista_destinatari.length;
String indice33="0";
if (indice21>0){
indice33="1";
}
fil_writ.addLineToFile("/home/davide/Documenti/progetto_s_e/sorgenti/messaggi_ADT.txt", indice33);*/
//Verifica se il messaggio è conforme all'XSD
//errori1=XsdShemaValidator.main(tipo+".xsd", "/home/davide/Documenti/progetto_s_e/sorgenti/temporaney.xml");
//Prepara la risposta
int errori2=errori0+errori1;
//vediamo se ci sono errori - OK no errori
/*String indice33="0";
if (errori2>0){
indice33="1";
}
fil_writ.addLineToFile("/home/davide/Documenti/progetto_s_e/sorgenti/messaggi_ADT.txt", indice33);*/
// set the response code and write the response data
resp.setStatus(HttpServletResponse.SC_OK);
OutputStreamWriter writer = new OutputStreamWriter(resp.getOutputStream());
if(errori2>0){
String risposta="messaggio non conforme xsd";
writer.write(risposta);
//test per vedere se entra qui - OK non entra
//fil_writ.addLineToFile("/home/davide/Documenti/progetto_s_e/sorgenti/messaggi_ADT.txt", risposta);
}
else{
String risposta = "il messaggio da te inviato:"+decodedString+"è stato ricevuto e processato";
writer.write(risposta);
if(Lista_destinatari!=null){
int indice1=Lista_destinatari.length;
//Test per vedere se arriva qui - OK ci arriva
//fil_writ.addLineToFile(/*"messaggi_"+tipo+".txt"*/"/home/davide/Documenti/progetto_s_e/sorgenti/messaggi_ADT.txt", decodedString+"|"+indice1);
while(indice1!=0){
fil_writ.addLineToFile(/*"messaggi_"+tipo+".txt"*/"/home/davide/Documenti/progetto_s_e/sorgenti/messaggi_"+tipo+".txt", decodedString+"|"+indice1);//Lista_destinatari[indice1]+"|");//aggiungi ad un file messaggio e indirizzi[i] separati da | e con in fondo |, questo file sarà usato poi dal pacchetto coda
indice1--;
}
}}
writer.flush();
writer.close();
} catch (IOException e) {
try{
resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
resp.getWriter().print(e.getMessage());
resp.getWriter().close();
} catch (IOException ioe) {
}
}
} // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
}
FileReaderTest.java
package classi_varie;
/**
*
* @author davide
*/
import java.io.*;
class FileReadTest {
public static void main (String[] args) {
FileReadTest f = new FileReadTest();
//args[0] contiene il nome del file dei messaggi, args[1] contiene il nome del file che contiene messaggi e indirizzi separati da | e terminanti con | a cui in prima istanza non ho potuto inviare, args[2] il tipo di quell'elenco di messaggi
//String nome_file = args[0];
String nome_file="/home/davide/Documenti/progetto_s_e/sorgenti/ciao.txt";
f.readMyFile(nome_file);
String[] righe_messaggi=f.readMyFile(args[0]);
String[] righe_mes_indirizzi= f.readMyFile(args[1]);
String[] indirizzi_a_cui_inviare=null;// = interroga database per rilevare tutti i destinatari interessati al tipo di evento args[2]
invia(righe_messaggi, indirizzi_a_cui_inviare);
ritenta(righe_mes_indirizzi);
}
String[] readMyFile(String nome_file) {
DataInputStream dis = null;
String record = null;
int recCount = 0;
String[] righe;
righe = new String[1000];
try {
File f = new File(nome_file);
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
while ( (record=dis.readLine()) != null ) {
recCount++;
System.out.println(recCount + ": " + record);
righe[recCount]=record;
}
System.out.println(righe[2]);
} catch (IOException e) {
// catch io errors from FileInputStream or readLine()
System.out.println("Uh oh, got an IOException error!" + e.getMessage());
} finally {
// if the file opened okay, make sure we close it
if (dis != null) {
try {
dis.close();
} catch (IOException ioe) {
}
}
}
return righe;
}
static void invia(String[] righe, String[] indirizzi){//righe contiene un messaggio per ogni riga, indirizzi un indirizzo a cui inviare per ogni riga
String provvisoria;
int i1=righe.length;
int i2=indirizzi.length;
while (i1>0){
provvisoria = righe[i1];
while (i2>0){
//Faccio il ReachableTest dell'indirizzo
//if(ritornoric!=null){
//invia righe[i1] a indirizzi[i2]}
//else{
//aggiungi ad un file righe[i1] e indirizzi[i2] separati da | e con in fondo |
//i2--
//}
}
i1--;
}
}
static void ritenta(String[] righe){//righe contiene un messaggio e l'indirizzo a cui inviarlo per ogni riga
String provvisoria;
int i1=righe.length;
while (i1>0){
int beg_seg = righe[i1].indexOf("|");
String messaggio=righe[i1].substring(0,beg_seg-1);
int end_string=righe[i1].lastIndexOf("|");
String indirizzo=righe[i1].substring(beg_seg+1,end_string-1);
//Faccio il ReachableTest dell'indirizzo
//if(ritornoric!=null){
//invia righe[i1] a indirizzi[i2]}
//else{
//aggiungi ad un file righe[i1] e indirizzi[i2] separati da | e con in fondo |
i1--;
}
i1--;
}
}
db1.java
package classi_varie;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
*
* @author davide
*/
public class db1 {
public static String[] main(String evento) throws ClassNotFoundException, SQLException{
System.out.println("Copyright 2004, R.G.Baldwin");
String nome_utente="root";
String password="260885";
evento="ADT";
String[] risultato1 = null;
try {
Statement stmt;
//Register the JDBC driver for MySQL.
Class.forName("com.mysql.jdbc.Driver");
//Define URL of database server for
// database named mysql on the localhost
// with the default port number 3306.
String url ="jdbc:mysql://localhost:3306/dispatcher";
//Get a connection to the database for a
// user named root with a blank password.
// This user is the default administrator
// having full privileges to do anything.
Connection con = (Connection) DriverManager.getConnection(url,nome_utente, password);
//Display URL and connection information
System.out.println("URL: " + url);
System.out.println("Connection: " + con);
//Get a Statement object
stmt = (Statement) con.createStatement();
ResultSet ris = stmt.executeQuery("SELECT * FROM tipi_messaggi"); /*WHERE tipi_messaggi.name='" + evento + "'");*/
ris.last();
int lunghezza_risultato=(int)ris.getInt("id");
String[] risultato=new String[lunghezza_risultato];
ris.first();
int indice=0;
ResultSet ris2 = stmt.executeQuery("SELECT * FROM tipi_messaggi"); /*WHERE tipi_messaggi.name='" + evento + "'");*/
while (ris2.next()) {
risultato[indice] = ris2.getString("id");//indirizzo destinatario
System.out.println(risultato[indice]);
}
con.close();
risultato1=risultato;
}catch( Exception e ) {
e.printStackTrace();
}//end catch
return risultato1;
}//end main
}//end class Jdbc12
fil_writ.java
package classi_varie;
/**
*
* @author davide
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
*
* @author davide
*/
public class fil_writ {
static public void addLineToFile(String file, String lineToadd) {
try {
File inFile = new File(file);
if (!inFile.isFile()) {
System.out.println("Parameter is not an existing file");
return;
}
//Construct the new file that will later be renamed to the original filename.
File tempFile = new File(inFile.getAbsolutePath() + ".tmp");
BufferedReader br = new BufferedReader(new FileReader(file));
PrintWriter pw = new PrintWriter(new FileWriter(tempFile));
String line = null;
//Read from the original file and write to the new
//unless content matches data to be removed.
while ((line = br.readLine()) != null) {
pw.println(line);
pw.flush();
}
pw.println(lineToadd);
pw.close();
br.close();
//Delete the original file
if (!inFile.delete()) {
System.out.println("Could not delete file");
return;
}
//Rename the new file to the filename the original file had.
if (!tempFile.renameTo(inFile))
System.out.println("Could not rename file");
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
static public void create_xml(String text, String file){
try {
File inFile = new File(file);
if (!inFile.isFile()) {
System.out.println("Parameter is not an existing file");
return;
}
PrintWriter pw = new PrintWriter(new FileWriter(file));
pw.println(text);
pw.close();
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}}
XsdSchemaValidator.java
package classi_varie;
/**
*
* @author davide
*/
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.XMLConstants;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.InputSource;
import javax.xml.validation.Validator;
import java.io.*;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ErrorHandler;
public class XsdShemaValidator {
private static int errorCount = 0;
int errori=0;
public static int main(String file_xsd, String file_xml) {
/*if (a.length<2) {
System.out.println("Usage:");
System.out.println("java XsdSchemaValidator schema_file_name "
+ "xml_file_name");
} else {*/
String schemaName = file_xsd;
String xmlName = file_xml;
Schema schema = loadSchema(schemaName);
validateXml(schema, xmlName);
//}
return errorCount;
}
public static void validateXml(Schema schema, String xmlName) {
try {
// creating a Validator instance
Validator validator = schema.newValidator();
// setting my own error handler
validator.setErrorHandler(new MyErrorHandler());
// preparing the XML file as a SAX source
SAXSource source = new SAXSource(
new InputSource(new java.io.FileInputStream(xmlName)));
// validating the SAX source against the schema
validator.validate(source);
System.out.println();
if (errorCount>0) {
System.out.println("Failed with errors: "+errorCount);
} else {
System.out.println("Passed.");
}
} catch (Exception e) {
// catching all validation exceptions
System.out.println();
System.out.println(e.toString());
}
}
public static Schema loadSchema(String name) {
Schema schema = null;
try {
String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
SchemaFactory factory = SchemaFactory.newInstance(language);
schema = factory.newSchema(new File(name));
} catch (Exception e) {
System.out.println(e.toString());
}
return schema;
}
private static class MyErrorHandler implements ErrorHandler {
public void warning(SAXParseException e) throws SAXException {
System.out.println("Warning: ");
printException(e);
}
public void error(SAXParseException e) throws SAXException {
System.out.println("Error: ");
printException(e);
}
public void fatalError(SAXParseException e) throws SAXException {
System.out.println("Fattal error: ");
printException(e);
}
private void printException(SAXParseException e) {
errorCount++;
System.out.println(" Line number: "+e.getLineNumber());
System.out.println(" Column number: "+e.getColumnNumber());
System.out.println(" Message: "+e.getMessage());
System.out.println();
}
}
}
ReachableTest.java
package coda;
/**
*
* @author davide
*/
import java.io.*;
import java.net.*;
public class ReachableTest {
public static boolean main(String indirizzo) {
boolean risultato=true;
try {
InetAddress address = InetAddress.getByName(indirizzo);
System.out.println("Name: " + address.getHostName());
System.out.println("Addr: " + address.getHostAddress());
System.out.println("Reach: " + address.isReachable(3000));
risultato=true;
}
catch (UnknownHostException e) {
System.err.println("Unable to lookup"+indirizzo);
risultato=false;
}
catch (IOException e) {
System.err.println("Unable to reach"+indirizzo);
risultato=false;
}
return risultato;
}
}
coda.java
package coda;
/**
*
* @author davide
*/
import java.io.*;
import java.lang.String;
import java.util.logging.Level;
import java.util.logging.Logger;
public class coda {
/*public static void main (String[] args) {
FileReadTest f = new FileReadTest();
//args[0] contiene il nome del file dei messaggi, args[1] contiene il nome del file che contiene messaggi e indirizzi separati da | e terminanti con | a cui in prima istanza non ho potuto inviare, args[2] il tipo di quell'elenco di messaggi
//String nome_file = args[0];
String nome_file="/home/davide/Documenti/progetto_s_e/sorgenti/ciao.txt";
f.readMyFile(nome_file);
String[] righe_messaggi=f.readMyFile(args[0]);
String[] righe_mes_indirizzi= f.readMyFile(args[1]);
String[] indirizzi_a_cui_inviare=null;// = interroga database per rilevare tutti i destinatari interessati al tipo di evento args[2]
invia(righe_messaggi, indirizzi_a_cui_inviare);
ritenta(righe_mes_indirizzi);
}*/
public static String[] readMyFile(String file_coda) {
DataInputStream dis = null;
String record = null;
int recCount = 0;
String[] righe;
righe = new String[1000];
try {
File f = new File(file_coda);
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
while ( (record=dis.readLine()) != null ) {
recCount++;
System.out.println(recCount + ": " + record);
righe[recCount]=record;
}
} catch (IOException e) {
// catch io errors from FileInputStream or readLine()
System.out.println("Uh oh, got an IOException error!" + e.getMessage());
} finally {
// if the file opened okay, make sure we close it
if (dis != null) {
try {
dis.close();
} catch (IOException ioe) {
}
}
}
return righe;
}
public static void ritenta(){//righe contiene un messaggio e l'indirizzo a cui inviarlo per ogni riga
String[] righe = readMyFile("coda.txt");
int i1=righe.length;
while (i1>0){
int beg_seg = righe[i1].indexOf("|");
String messaggio=righe[i1].substring(0,beg_seg-1);
int end_string=righe[i1].lastIndexOf("|");
String indirizzo=righe[i1].substring(beg_seg+1,end_string-1);
boolean risultato=ReachableTest.main(indirizzo);
if(risultato=true){
try {
send.main(messaggio, indirizzo);
} catch (Exception ex) {
Logger.getLogger(coda.class.getName()).log(Level.SEVERE, null, ex);
fil_writ.addLineToFile("coda.txt", messaggio+"|"+indirizzo+"|");//aggiungi ad un file messaggio e indirizzi[i] separati da | e con in fondo |
}
}
else{
fil_writ.addLineToFile("coda.txt", messaggio+"|"+indirizzo+"|");//aggiungi ad un file messaggio e indirizzi[i] separati da | e con in fondo |
}
i1--;
}
}
public static void invia(){//righe contiene un messaggio per ogni riga, indirizzi un indirizzo a cui inviare per ogni riga
String[] righe = readMyFile("messaggi_ADT.txt");
int i1=righe.length;
while (i1>0){
int beg_seg = righe[i1].indexOf("|");
String messaggio=righe[i1].substring(0,beg_seg-1);
int end_string=righe[i1].lastIndexOf("|");
String indirizzo=righe[i1].substring(beg_seg+1,end_string-1);
boolean risultato=ReachableTest.main(indirizzo);
if(risultato=true){
try {
send.main(messaggio, indirizzo);
} catch (Exception ex) {
Logger.getLogger(coda.class.getName()).log(Level.SEVERE, null, ex);
fil_writ.addLineToFile("coda.txt", messaggio+"|"+indirizzo+"|");//aggiungi ad un file messaggio e indirizzi[i] separati da | e con in fondo |
}
}
else{
fil_writ.addLineToFile("coda.txt", messaggio+"|"+indirizzo+"|");//aggiungi ad un file messaggio e indirizzi[i] separati da | e con in fondo |
}
i1--;
}
}
}
fil_writ.java
package coda;
/**
*
* @author davide
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
*
* @author davide
*/
public class fil_writ {
static public void addLineToFile(String file, String lineToadd) {
try {
File inFile = new File(file);
if (!inFile.isFile()) {
System.out.println("Parameter is not an existing file");
return;
}
//Construct the new file that will later be renamed to the original filename.
File tempFile = new File(inFile.getAbsolutePath() + ".tmp");
BufferedReader br = new BufferedReader(new FileReader(file));
PrintWriter pw = new PrintWriter(new FileWriter(tempFile));
String line = null;
//Read from the original file and write to the new
//unless content matches data to be removed.
while ((line = br.readLine()) != null) {
pw.println(line);
pw.flush();
}
pw.println(lineToadd);
pw.close();
br.close();
//Delete the original file
if (!inFile.delete()) {
System.out.println("Could not delete file");
return;
}
//Rename the new file to the filename the original file had.
if (!tempFile.renameTo(inFile))
System.out.println("Could not rename file");
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
static public void create_xml(String text, String file){
try {
File inFile = new File(file);
if (!inFile.isFile()) {
System.out.println("Parameter is not an existing file");
return;
}
PrintWriter pw = new PrintWriter(new FileWriter(file));
pw.println(text);
pw.close();
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}}
send.java
package coda;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
/**
*
* @author davide
*/
public class send {
public static void main(String messaggio, String indirizzo) throws Exception {
/*if (args.length != 2) {
System.err.println("Usage: java Reverse " +
"http://localhost:8081/http_service/Servlet1" +
" string_to_reverse");
System.exit(1);
}*/
//String messaggio_da_inviare="davide sei forte";
String stringToReverse = URLEncoder.encode(messaggio, "UTF-8");
URL url = new URL(indirizzo);//args[0]);"http://localhost:8081/http_service/Servlet1"
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(
connection.getOutputStream());
out.write("string=" + stringToReverse);
out.close();
BufferedReader in = new BufferedReader(
new InputStreamReader(
connection.getInputStream()));
String decodedString;
while ((decodedString = in.readLine()) != null) {
System.out.println(decodedString);
}
in.close();
}
}
Contatto:
dew85@tiscali.it