In effetti una definizione piu' tecnica di middleware e' indipendente dai database e consiste nel considerare come tale, tutto il software indipendente da una particolare applicazione, che utilizza i servizi base di rete come il TCP-IP. Insomma nella gerarchia a strati che definisce le reti, il middleware si situa nello strato intermedio tra quello di TCP-IP e quello delle applicazioni. Da questo punto di vista piu' generale vanno considerati come middleware: emulatori di terminali, WWW, Corba,rpc, etcJava puo' comunicare con un data base attraverso 3 diversi meccanismi:
Il middleware vero e proprio viene invece realizzato attraverso la tecnica
RMI che vedremo prima indipendentemente dal problema del database, e poi
applicata per "pubblicare" sul Web un database ad oggetti. La stessa tecnica
puo' essere usata per interfacciare al Web un database relazionale, ma qui
non sara' considerata, in quanto al momento attuale esistono numerose
soluzioni alternative a Java e tutte piu' semplici da realizzare.
Ci sono vari tipi o modelli di database
ma il piu' comune e' il database relazionale che si presenta appunto come
una serie di tabelle e di relazioni tra le stesse.
Per i data base relazionali o RDBMS e' stato creato un linguaggio standard di creazione
e interrogazione di database che permette la comunicazione con RDBMS
. Il linguaggio si chiama SQL o Structured Query
Language ed e' capito dalla maggioranza dei database
.Esso prevede otto tipi di dati:
L'uso del formato XML per interfacciarsi al Database e' venuto fuori solo
da poco ed e' facilitato in Java da JAXP (Java API for XML Processing )
che e' ormai, dalla versione 1.4, parte integrante di Java.
Interfacciamento a data base relazionali SQL con JDBC
Inoltre nel gergo dei database relazionali le righe di una tabella sono
record e le colonne sono campi(fields in inglese).
Ogni campo e' individuato da un nome ed ogni record da uno o piu' campi particolari
che fanno da identificatore o chiave primaria dello stesso.
I DBMS piu'
diffusi come MySQL , Oracle e Access sono relazionali.
In effetti nel gergo relazionale il termine relazione non indica la "relazione" tra due tabelle ma la stessa tabella. Si intende che
e' sempre possibile rappresentare tutto il database con un'unica enorme tabella
e le "relazioni" nel senso di collegamenti sono rappresentati dalle colonne.
Quando dividiamo questa tabella in tabelle piu' piccole questi collegamenti
sono rappresentati da colonne nelle due tabelle che hanno uguali valori.
Questo processo si indica col nome di "normalizzazione" ed e' una delle cose
piu' difficili da fare nel disegno di database relazionali.
Tipo di dati | Dichiarazioni |
Numeri | INTEGER,DECIMAL(m,n),REAL... |
Stringhe di caratteri | CHARACTER(N),TEXT |
Stringhe di bit | |
Data | |
Ora | |
Timestamp | |
Durata |
Un programma che acceda a un database usando SQL dovrebbe poter essere usato con database di diverso tipo,basta che capiscano l'SQL. Esistono al momento attuale almeno 3 interfacce standard per database SQL: Microsoft ODBC, Java JDBC e Perl DBI. In particolare Java contiene un pacchetto applicativo che permette di scrivere programmi di accesso a database relazionali. Perche' questo avvenga il costruttore di un particolare database deve fornire un insieme di classi detto JDBC driver che contiene le caratteristiche specifiche del database.
Per questo, se volete accedere a un database MySQL, dovete:
Nell'applicazione che segue useremo la tabella Persone
.
Ecco le istruzioni su come
caricare la stessa tabella in MySQL.
Applicazione 1:Accesso a tabella MySQL da applicazione e da applet. S
file Persone.java
/* * This sample shows how to list all the names from the Persone table */ // You need to import the java.sql package to use JDBC import java.sql.*; class Persone { public static void main (String args []) { try { // Load the Mysql JDBC driver try { Class.forName("org.gjt.mm.mysql.Driver"); } catch (ClassNotFoundException e) { System.out.println ("Mysql device driver does not exist"); System.exit(1); } // Connect to the database // You can put a database name after the @ sign in the connection URL. Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/Persone?user=Persone&password="); // Create a Statement Statement stmt = conn.createStatement (); // Select the ENAME column from the EMP table ResultSet rset = stmt.executeQuery (" select ID, Cognome, Nome, Tel , Email,Homepage from Persone"); // Iterate through the result and print the employee names while (rset.next ()) { System.out.println (rset.getString (1)+" "+rset.getString(2)+" "+ rset.getString(3)+" "+rset.getString(4)+" "+rset.getString(5)); } // Close the RseultSet rset.close(); // Close the Statement stmt.close(); // Close the connection conn.close(); } catch (SQLException e) { System.out.println("Error accessing DB "); System.out.println(" Error code is : "+e.getErrorCode()); System.out.println(" Error message is :"+e.getMessage()); } } }
Connection
permette di connettersi al database.
Statement
permette di fare la query in SQL.
ResultSet
permette di ottenere le righe risultato della domanda.
setenv CLASSPATH ".:/user/gruppo_1/zito/mm.mysql.jdbc-1.2c/mysql_comp.jar"
localhost
indica che ci troviamo sullo stesso computer che contiene il database. MySQL
prevede anche l'accesso da computer remoti.
file PersoneApplet.java
/* * This sample shows how to list all the names from the Persone table */ // You need to import the java.sql package to use JDBC import java.sql.*; import java.awt.*; import java.applet.*; public class PersoneApplet extends Applet { TextArea ta = new TextArea("In attesa di connessione...",30,70); public void init() { setLayout(new BorderLayout()); add("Center",ta); try { // Load the Mysql JDBC driver try { Class.forName("org.gjt.mm.mysql.Driver"); } catch (ClassNotFoundException e) { System.out.println ("Mysql device driver does not exist"); System.exit(1); } // Connect to the database // You can put a database name after the @ sign in the connection URL. Connection conn = DriverManager.getConnection ("jdbc:mysql://alboot.ba.infn.it/Persone?user=Persone&password="); // Create a Statement Statement stmt = conn.createStatement (); // Select the ENAME column from the EMP table ResultSet rset = stmt.executeQuery (" select ID, Cognome, Nome, Tel , Email,Homepage from Persone"); StringBuffer buf = new StringBuffer(); // Iterate through the result and print the employee names while (rset.next ()) { buf.append (rset.getString (1)+" "+rset.getString(2)+" "+ rset.getString(3)+" "+rset.getString(4)+" "+rset.getString(5)+"\n"); } ta.setText(buf.toString()); // Close the RseultSet rset.close(); // Close the Statement stmt.close(); // Close the connection conn.close(); } catch (SQLException e) { System.out.println("Error accessing DB "); System.out.println(" Error code is : "+e.getErrorCode()); System.out.println(" Error message is :"+e.getMessage()); } } }Prova l'applet qui.
alboot.ba.infn.it
invece
di localhost
nel nome del database.
file Insert.java
import java.sql.*; class Insert { public static void main (String args []) throws SQLException { // Load the Mysql JDBC driver try { Class.forName("org.gjt.mm.mysql.Driver"); } catch (ClassNotFoundException e) { System.out.println ("Mysql device driver does not exist"); System.exit(0); } // Connect to the database // You can put a database name after the @ sign in the connection URL. Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/Persone?user=Persone&password="); // Create a Statement Statement stmt = conn.createStatement (); stmt.executeUpdate ("drop table COFFEES"); String createString; createString = "create table COFFEES " + "(COF_NAME varchar(32), " + "SUP_ID int, " + "PRICE float, " + "SALES int, " + "TOTAL int)"; stmt.executeUpdate (createString); System.out.println("Table COFFEES created"); int r=0; r+=stmt.executeUpdate ("insert into COFFEES values ('Colombian', 101, 7.99, 0, 0)"); r+=stmt.executeUpdate ("insert into COFFEES values ('Espresso', 150, 9.99, 0, 0)"); System.out.println("A total of "+r+" rows were inserted"); // Close the Statement stmt.close(); // Close the connection conn.close(); } }
drop
per cancellare la tabella creata dalla
prova precedente.
create
per creare la tabella e definire lo schema
della stessa.
file Update.java
// You need to import the java.sql package to use JDBC import java.sql.*; class Update { public static void main (String args []) throws SQLException { // Load the Mysql JDBC driver try { Class.forName("org.gjt.mm.mysql.Driver"); } catch (ClassNotFoundException e) { System.out.println ("Mysql device driver does not exist"); System.exit(0); } // Connect to the database // You can put a database name after the @ sign in the connection URL. Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/Persone?user=Persone&password="); // Create a Statement Statement stmt = conn.createStatement (); String s = "update COFFEES set PRICE=15.99 where COF_NAME='Espresso'"; int r = stmt.executeUpdate (s); r+=stmt.executeUpdate ("delete from COFFEES where price < 8."); System.out.println(r+" rows where updated/modified"); // Close the Statement stmt.close(); // Close the connection conn.close(); } }
update
I programmi JDBC possono girare negli applet se il database permette l'accesso remoto (un applet puo' comunicare solo con servizi Internet del server dal quale proviene e "jdbc" viene considerato un servizio Internet). Quindi Jdbc in alcuni casi si presta a realizzare middleware. Questo e' vero per MySQL se l'amministratore abilita l'accesso remoto al database. In caso contrario dovete richiamare il programma come un CGI script, o meglio ancora come un servlet in un server opportunamente abilitato a eseguire programmi Java (ad es. Apache). La soluzione che vedremo fra poco (RMI) e' invece sempre applicabile in quanto "rmi" e' un servizio Internet e puo' essere usato assieme a JDBC per rendere un data base relazionale accessibile da un'applet.
In particolare questa puo' avvenire in due modi:
Livello | Client | Server |
programma | programma che usa l'oggetto remoto | programma che rende disponibili gli oggetti remoti |
richiamo locale del metodo | attraverso Object Stub | attraverso Object Skeleton |
Protocollo di scambio oggetti:CORBA o RMI | Scambio di oggetti | |
Protocolli di rete:http,TCP,UDP,... | Connessione attraverso socket | |
Livello hardware |
Ogni protocollo di livello superiore ha bisogno dei livelli inferiori per funzionare.
Ogni oggetto remoto ha un suo indirizzo standard (URL) che gli permette di rendersi accessibile attraverso un servizio detto RMI Registry(simile se vogliamo al DNS). Per
questo il computer che ospita
gli oggetti remoti deve far girare 3 programmi:
Anche il computer che gira il client ,in certi casi, potrebbe aver bisogno
di un server Web.
La soluzione? Collegare ai tasti di selezione eventi l'indirizzo di un CGI
script, un programma in Fortran che provvede ad accedere ai dati e a processarli
ritornando le coordinate in un documento di testo HTML.
La soluzione ottimale e' nello scrivere "un server di eventi" che faccia da
interfaccia tra l'applet e la sorgente degli eventi. Questo server potrebbe
essere un semplice server Web modificato (vedi l'Applicazione 6 della
lezione 7) oppure possiamo sviluppare una soluzione ancora piu' sofisticata
attraverso RMI. Cio' che ora vedremo...
La messa a punto di un collegamento RMI e' una cosa complessa che richiede
numerosi passi:
file Compute.java
file ComputeEngine.java
file Server.java
file Client.java
In definitiva ecco i passi da compiere per far girare questo esempio su alboot:
file Compute.java
file Bakelite.java
file ComputeEngine.java
file Server.java
file Client1.java
file ClientApplet.java
Objectivity/DB si occupa di memorizzare i soli attributi di una classe
lasciando all'applicazione il compito di definirne il comportamento
con opportuni metodi.Inoltre e' possibile definire associazioni
tra oggetti unidirezionali e bidirezionali, uno a uno , uno a molti e
molti a molti. Si tiene conto delle associazioni nella memorizzazione
degli oggetti e nelle operazioni di cancellazione e locking.
L'unita' di trasferimento tra il database e l'applicazione non e' l'oggetto
ma la pagina di oggetti, per cui Objectivity/DB e' un database di tipo
page server e non object server.
L'api Java di Objectivity contiene i seguenti oggetti principali:
Per usare RMI come livello di mezzo tra l'utente che lavora con l'applet
su un qualsiasi computer collegato a Internet e il database Objectivity/DB
avremo bisogno che sulla macchina server girino contemporaneamente:
Nell'esempio che mostriamo abbiamo un unico contenitore l'oggetto
file FillDetector.java
file IObject.java
file Record.java
file Bakelite.java
file Wheel.java
file BakeliteData.java
Gli oggetti Da come e' stato creato il database, dovrebbe essere chiara la strategia
usata per rendere gli oggetti accessibili all'applet client.
Gli oggetti persistenti sono oggetti remoti e percio' implementano
una serie di metodi definiti nell'interfaccia file Compute.java
file ComputeEngine.java
file Server.java
file Client.java
file Compute2.java
file Server2.java
file Client2.java
file ClientApplet2.java
Per concludere vediamo come si estende questo schema per poter accedere
a un qualsiasi oggetto di un database distribuito costituito magari
da decine di federated database sparsi in tutto il momdo.
Oppure,riferendoci all'esempio visto prima del display di eventi, cosa
facciamo se l'evento puo' risiedere su uno qualsiasi di centinaia di computer
collegati a Internet e sparsi in tutto il mondo?
Dotiamo ogni computer di un server RMI di eventi. Quando facciamo la
richiesta di un particolare evento questa viene inviata a un qualsiasi
server, ad esempio il piu' vicino. Questi puo' trovare l'evento e restituircelo
oppure inoltrare la richiesta a un altro server. Cosi' la richiesta si propaga
da un server all'altro finche' qualche server non trova l'evento.
Ora sostituite agli eventi un brano di musica mp3 oppure un qualsiasi
file , ed ecco trovato il modo di condividere brani di musica o file con
tutti gli altri utenti della rete.Cioe' musica gratis o quasi (dovete avere
il vostro computer collegato a Internet 24/24 con una linea abbastanza veloce).
file Loadxml.java
file Persone.java
file Readxml.java
file Displayxml.java
file Displaynews.java
Per capire l'uso del server Web in queste applicazioni, bisogna tener
conto del fatto che una macchina virtuale Java ha la possibilita'
di rendere disponibili le classi ad essa accessibili localmente a macchine virtuali remote, tramite un server Web. Questo si fa impostando la
proprieta' codebase
. In questo modo,ad esempio,il
client puo' ottenere lo stub dal server.
In alternativa, lo stub e altre classi del server che servono al client,possono
essere copiate a mano all'inizio,una volta per tutte.
Per riuscire a capire che tipo di servizio viene offerto da un server di oggetti,
consideriamo il problema concreto di realizzare un display di eventi delle alte energie come questo interamente in Java. Non e' difficile costruire la parte grafica di questo programma, ma ad un certo punto ci troveremo col problema di interfacciare questo
programma con la sorgente degli eventi. Non si tratta solo di leggere un file,
ma di usare numerosi sottoprogrammi scritti in Fortran e C che e' impensabile
riscrivere in Java e che ci permettono di passare dai dati "bruti" alle coordinate degli oggetti da rappresentare.
Funziona? Si, ma se piu' utenti richiedono nello stesso momento eventi
e' il disastro in quanto il sistema non e' in grado di gestire piu' richieste
contemporanee.
Da notare che il client deve avere accesso
ai seguenti pezzi di codice remoti:
Remote
e che definiscono tutti i metodi
remoti.Nell'esempio che segue l'interfaccia si chiama Compute
.
ComputeEngine
Questa classe deve estendere UnicastRemoteObject
.
rmic ComputeEngine
rmi://remotehost/nomeservizio
.Quindi usa l'indirizzo dell'oggetto
per richiamare i suoi metodi remoti.Se sul computer che ospita il server, non
e' disponibile un server Web, bisogna ricordarsi di copiare a mano tutte le classi che servono.
Inoltre il client puo' a sua volta trasformarsi in server
in modo da permettere al server remoto di comunicare per riferire eventuali
problemi.
Bisogna fare attenzione a distinguere tra oggetti remoti e oggetti locali.Gli oggetti remoti hanno stubs e skeleton definiti e sono trasferiti
solo per riferimento.Invece gli oggetti locali, se presenti come parametri
o valore ritornato in una invocazione a metodo remoto, vengono trasferiti per valore. Perche' questo sia possibile devono essere serializzabili, cioe'
implementare l'interfaccia Serializable
.Questo significa anche
che la loro modifica agisce solo sulla copia locale.
Applicazione 4:Client e Server Java RMI . S
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Compute extends Remote {
int executeCalculation (int i) throws RemoteException;
String tellmeWhoYouAre (String name) throws RemoteException;
}
import java.rmi.*;
import java.rmi.server.*;
public class ComputeEngine extends UnicastRemoteObject
implements Compute
{
private String id;
private int count=0;
public ComputeEngine(String _id) throws RemoteException {
super();
id = _id;
}
public int executeCalculation(int i) {
System.out.println("Calculation performed with: "+i);
count=count+i;
return count;
}
public String tellmeWhoYouAre(String name) {
String s = new String("Hello, "+name+" I'm Calculator "+id);
System.out.println("Greeting "+name);
return s;
}
}
Compute.java
viene implementata
definendo il codice dei due metodi executeCalculation
e
tellmeWhoYouAre
.
import java.rmi.*;
import java.rmi.server.*;
public class Server
{
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Compute engine1 = new ComputeEngine("32");
Naming.rebind("Compute32", engine1);
Compute engine2 = new ComputeEngine("33");
Naming.rebind("Compute33", engine2);
System.out.println("ComputeEngine bound");
} catch (Exception e) {
System.err.println("ComputeEngine exception: " + e.getMessage());
e.printStackTrace();
}
}
}
Security Manager
ComputeEngine
coi nomi
"Compute32" e "Compute33".
import java.rmi.*;
public class Client {
public static void main (String args[]) {
if (System.getSecurityManager()==null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//"+args[0]+"/"+args[1];
Compute comp = (Compute) Naming.lookup(name);
int i=comp.executeCalculation(1);
System.out.println("Calculation result is "+i);
String s = comp.tellmeWhoYouAre("the Client");
System.out.println("Greeiting is "+s);
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
}
Se non si fa uso del server Web sul computer dove gira il Server
allora Stub e ComputeEngine vanno copiati a mano (ad es. con ftp) sul
computer e la cartella del client. Allora basta far partire client e server
coi comandi:
ind
richiamando il metodo Naming.lookup(ind)
java Server
java Client alboot.ba.infn.it Compute32
se si fa uso del server Web allora l'istruzione per far partire il server e' piu' complicata:
java -Djava.security.policy=java.policy -Djava.rmi.server.hostname=alboot.ba.infn.it -Djava.rmi.server.codebase="http://www.ba.infn.it/~zito/jsem/java/sem8/step1/server/" Server
e il file java.policy
deve contenere:
grant {
permission java.net.SocketPermission "*:1024-65535", "connect,accept";
permission java.net.SocketPermission "*:80", "connect";
};
server
rmiregistry &
startserver &
client
java Client alboot.ba.infn.it Compute32
Applicazione 5:Client e Server Java RMI con invio di oggetto da server a client. S
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Compute extends Remote {
int executeCalculation (int i) throws RemoteException;
String tellmeWhoYouAre (String name) throws RemoteException;
Bakelite getBakelite (int id) throws RemoteException;
}
import java.io.*;
public class Bakelite implements Serializable{
String code;
int id;
double dati[] = new double[30];
Bakelite(int id){
code = "codicexx";
this.id = id;
for(int i=0;i<30;i++){dati[i]=Math.random()*10000.;}
}
}
import java.rmi.*;
import java.rmi.server.*;
public class ComputeEngine extends UnicastRemoteObject
implements Compute
{
private String id;
private int count=0;
public ComputeEngine(String _id) throws RemoteException {
super();
id = _id;
}
public int executeCalculation(int i) {
System.out.println("Calculation performed with: "+i);
count=count+i;
return count;
}
public String tellmeWhoYouAre(String name) {
String s = new String("Hello, "+name+" I'm Calculator "+id);
System.out.println("Greeting "+name);
return s;
}
public Bakelite getBakelite(int id) {
Bakelite bak = new Bakelite(id);
System.out.println("sending "+bak);
return bak;
}
}
import java.rmi.*;
import java.rmi.server.*;
public class Server
{
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Compute engine1 = new ComputeEngine("32");
Naming.rebind("Compute32", engine1);
Compute engine2 = new ComputeEngine("33");
Naming.rebind("Compute33", engine2);
System.out.println("ComputeEngine bound");
} catch (Exception e) {
System.err.println("ComputeEngine exception: " + e.getMessage());
e.printStackTrace();
}
}
}
import java.rmi.*;
public class Client1 {
public static void main (String args[]) {
if (System.getSecurityManager()==null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//"+args[0]+"/"+args[1];
Compute comp = (Compute) Naming.lookup(name);
int i=comp.executeCalculation(1);
System.out.println("Calculation result is "+i);
String s = comp.tellmeWhoYouAre("the Client");
System.out.println("Greeiting is "+s);
Bakelite b = comp.getBakelite(20);
System.out.println("Bakelite is "+b.id+" "+b.code+" "+b.dati[0]);
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
getBakelite
.
Bakelite
implementa Serializable
in modo che possa essere serializzato e inviato attraverso Internet.
Client1
Applet6:Come il precedente ma ora usa un applet come client . S
import java.rmi.*;
import java.awt.*;
import java.applet.*;
public class ClientApplet extends Applet {
Bakelite b;
public void init(){
if (System.getSecurityManager()==null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//alboot.ba.infn.it/Compute32";
Compute comp = (Compute) Naming.lookup(name);
int i=comp.executeCalculation(1);
System.out.println("Calculation result is "+i);
String s = comp.tellmeWhoYouAre("the Client");
System.out.println("Greeiting is "+s);
b = comp.getBakelite(20);
System.out.println("Bakelite is "+b.id+" "+b.code+" "+b.dati[0]);
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
public void paint(Graphics g){
g.drawString("Bakelite"+b.id,5,25);
}
}
Prova l'applet qui.
In definitiva, un server RMI, a differenza dello script CGI che ha
la funzionalita' di un singolo programma, puo' fornire :
Uso di RMI per interfacciare un database ad oggetti
Il server RMI in questo caso risiede sullo stesso computer dove si trova
il database ad oggetti e fornisce gli oggetti del database al client
remoto realizzato con un'applet.
Il database ad oggetti e' realizzato da Objectivity/DB che e'
in grado di gestire oggetti persistenti con i seguenti tipi di attributi.
Tipo Descrizione
int8, int16, int32, int64 Interi
float32, float64 Floating Point
ooVString Stringa di caratteri ASCII di lunghezza variabile
ooUTF8String Stringa di caratteri Unicode di lunghezza variabile
ooVArray(type) Array di dimensione variabile
ooRef(class) Riferimento a oggetto
ooVArray(ooRef(class)) Array di riferimenti
Gli oggetti sono quindi raggruppati in contenitori(pagina di oggetti), in database (singoli files), in federated database o federazioni(insieme di files+catalogo+
schema dei dati+boot file).Il singolo oggetto in un federated database ha
un identificatore unico detto OID che serve per rintracciarlo.Una federazione Objectivity puo' essere distribuita su piu' computer collegati via TCP/IP.
Per questo la gestione di database Objectivity prevede oltre a un server locale
anche un server remoto(AMS nel gergo Objectivity) che provvede a comunicare con la parte di federazione
memorizzata su altri computer.Questa possibilita' di distribuire il database
rende Objectivity capace di gestire database molto piu' grandi di quelli
relazionali che sono limitati dal fatto di essere costretti a girare su un solo
computer.
Ogni oggetto che estende la classe ooObj e' persistente.
L'interazione tra applicazione e database avviene durante una sessione tra il
session.begin()
e il session.commit()
.Solo allora
un oggetto persistente e' davvero persistente : in ogni caso esso deve
essere esplicitamente letto dal db col metodo fetch()
e scritto
con markModified
ogni volta che e' necessario. L'interazione
col database avviene per transazioni in modo da preservare l'integrita'
dei dati.
Un programma detto lock server provvede a rinforzare i lock richiesti
durante le transazioni. Esso di solito gira su un computer apposito e diverso
da quello del database.
Le transazioni, che esistono anche per i database relazionali, sono
un'importante caratteristica dei database in quanto ,assieme al locking,
permettono l'uso di un database da parte di piu' utenti senza
che le modifiche di un utente interferiscano con quelle degli altri.
Una transazione indica una serie di
operazioni che devono essere eseguite insieme.
Se tutte le operazioni hanno successo, allora viene dato il commit
e il data base e' aggiornato, altrimenti avviene il roll back
e tutto torna a come era prima della transazione. (Immaginate un trasferimento
di denaro in banca...). MySQL non ha le transazioni ma permette il lock
di una tabella durante operazioni delicate.
Per far girare l'applicazione presentata dovremo percio' procedere coi passi
seguenti:
Gli oggetti persistenti sono resi remoti in modo che i loro metodi possano
essere usati, ma non viaggiano in rete. L'applet puo' comunque
riferirsi a un qualsiasi oggetto persistente utilizzando il suo OID che
come abbiamo visto e' univoco. Inoltre esso puo' ricavare i valori dei
vari attributi attraverso i metodi dell'oggetto.Essenzialmente, quando
l'applet richiede gli oggetti di un contenitore, riceve un vettore di
OID che puo' usare per ricavare ulteriori informazioni.Questo modo di procedere
e' necessario perche' come abbiamo visto prima, la persistenza e' assicurata
solo nel server e durante una transazione: se noi facessimo viaggiare gli
oggetti persistenti, nulla ci assicura che al loro arrivo gli attributi non
siano stati cambiati nel frattempo.
oocheckls lockcms
e ools
oodeletefd RPC
createRPC.sh
.Questo script invoca i comandi di Objectivity per creare il database.
fillRPC.sh
.
ootoolmgr
Wheel
che contiene 10000 oggetti Bakelite
.
Applicazione 7:Crea un Data Base Objectivity
S
import com.objy.db.*;
import com.objy.db.app.*;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import java.io.*;
public class FillDetector {
Connection conn;
Session session;
ooFDObj fd;
ooDBObj db;
public static void main (String args[]) {
(new FillDetector()).go(args);
}
void go(String[] args) {
try {
conn = Connection.open ("RPC", oo.openReadWrite);
System.out.println ("Connection to RPC-database opened");
session = new Session();
session.begin();
conn.getSchemaPolicy().setChangeClassAllowed(false);
conn.getSchemaPolicy().setFieldAccessControlEnforced(false);
conn.setSchemaClassName("Bakelite","Bakelite");
conn.getSchemaPolicy().setFieldAccessControlEnforced(false);
checkDB("RPCdata");
checkCont();
if (checkBakelite())
System.out.println("Bakelite plates objects already exist");
else {
System.out.print("Adding Bakelite plates objects ...");
addBakelite();
System.out.println(" done");
session.checkpoint();
}
session.commit();
session.terminate();
conn.close();
} catch (DatabaseNotFoundException exception) {
System.out.println("Federated database \"Detector\" not found.");
} catch (Exception e) {
System.out.println("Exception in FillDetector: " + e.getMessage());
e.printStackTrace();
}
}
void checkDB(String db_name) {
/* check if the CMS database exists, otherwise create it */
fd = session.getFD();
if (fd.hasDB(db_name)) {
System.out.println("Database " + db_name + " exists");
db = fd.lookupDB(db_name);
} else {
db = fd.newDB(db_name);
System.out.println("Database " + db_name + " created");
}
}
void checkCont() {
/* check if the Wheel<-2..2> containers exist, otherwise create them */
for (int i=2; i<3; i++) {
String contName = "Wheel" + (i-2 <= 0 ?
String.valueOf(i-2) :
"+" + String.valueOf(i-2));
if (db.hasContainer(contName)) {
System.out.println(contName + " container exists");
} else {
Wheel cont = new Wheel();
db.addContainer(cont, contName, 0, 500, 20);
System.out.println(contName + " container created");
}
}
}
boolean checkBakelite() {
/* check if there are some bakelite plates around */
Iterator itr = db.scan ("Bakelite");
return itr.hasMoreElements();
}
void addBakelite() {
/* add some random chambers to the Detector database */
for (int i=2; i<3; i++) {
String contName = "Wheel" + (i-2 <= 0 ?
String.valueOf(i-2) :
"+" + String.valueOf(i-2));
Wheel cont = (Wheel)db.lookupContainer(contName);
/* for (int j=0; j<4; j++) {
String mb_type = "MB" + String.valueOf(j%4+1); */
for (int k = 0; k < 10000; k++) {
Bakelite c = new Bakelite (k,"Codicexx",Math.random()*10000,
Math.random()*10000,
Math.random()*10000);
cont.cluster(c);
}
}
}
}
package remote;public interface IObject extends java.rmi.Remote {
Record getAttrs() throws java.rmi.RemoteException;
void setAttrs(Record r) throws java.rmi.RemoteException;
String asString() throws java.rmi.RemoteException;
java.util.Vector getPathInfo() throws java.rmi.RemoteException;}
public interface Record extends java.io.Serializable {}
import com.objy.db.app.*;
import java.util.Date;
import java.util.Vector;
import java.util.Enumeration;
public class Bakelite extends ooObj implements IObject {
int id;
String codice;
double dato1;
double dato2;
double dato3;
public Bakelite() {}
public Bakelite (int id, String codice, double dato1, double dato2,
double dato3 ) {
this.id = id;
this.codice = codice;
this.dato1 = dato1;
this.dato2 = dato2;
this.dato3 = dato3; }
/* local methods */
public void setcodice(String codice) {
markModified();
this.codice = codice;
}
public String getcodice() {
fetch();
return codice;
}
public void setid(int id) {
markModified();
this.id = id;
}
public int getid() {
fetch();
return id;
}
public void setdato1(double dato1) {
markModified();
this.dato1 = dato1;
}
public void setdato2(double dato2) {
markModified();
this.dato2 = dato2;
}
public void setdato3(double dato3) {
markModified();
this.dato3 = dato3;
}
public double getdato1() {
fetch();
return dato1;
}
public double getdato2() {
fetch();
return dato2;
}
public double getdato3() {
fetch();
return dato3;
}
public String toString() {
fetch();
return "Bakelite " + this.id;
}
/* remote methods */
public String asString() { return toString(); }
public Vector getPathInfo() {
Wheel cont = (Wheel) getContainer();
String contName = cont.getName();
char[] wheelChars = contName.toCharArray();
int wheel = wheelChars[contName.length()-1] - 48;
if (wheelChars[contName.length()-2] == '-')
wheel = -wheel;
String bak_type = getcodice();
int type = bak_type.toCharArray()[bak_type.length()-1] - 48;
int bakelite = getid();
Vector result = new Vector(3);
result.addElement (new Integer(wheel + 2));
result.addElement (new Integer(type - 1));
result.addElement (new Integer(bakelite - 1));
return result;
}
public Record getAttrs() {
return new BakeliteData(this);
}
public void setAttrs(Record r) {
if (r instanceof BakeliteData) {
BakeliteData data = (BakeliteData) r;
setid(data.id);
setcodice(data.codice);
setdato1(data.dato1);
setdato2(data.dato2);
setdato3(data.dato3);
}
}
}
import com.objy.db.app.ooContObj;
public class Wheel extends ooContObj {
public String toString() {
fetch();
return this.getName();
}
}
/* import db.*; */
public class BakeliteData implements Record {
public int id;
public String codice;
public double dato1;
public double dato2;
public double dato3;
public BakeliteData (int id, String codice, double dato1, double dato2,
double dato3 ) {
this.id = id;
this.codice = codice;
this.dato1 = dato1;
this.dato2 = dato2;
this.dato3 = dato3; }
public BakeliteData(Bakelite bak) {
id = bak.getid();
codice = bak.getcodice();
dato1 = bak.getdato1();
dato2 = bak.getdato2();
dato3 = bak.getdato3();
}
}
Prima di far girare il programma che ha FillDetector
come classe
principale, occorre cancellare il database creato precedentemente
e crearne uno nuovo con le istruzioni:
oodeletefd RPC
oonewfd -fdfilepath /afs/cern.ch/user/g/gzito/cms/RPC.fdb -fdnumber 3627 -pagesize 1024 -lockserverhost lockcms RPC
Se sono rimasti dei lock pendenti e' impossibile cancellare il database:
bisogna prima rilasciare questi lock con oocleanup RPC
.
La lista dei lock si puo' ottenere con oolockmon RPC
.
Bakelite
diventano persistenti solo dopo
l'istruzione conn.cluster(c)
in via temporanea. La fine
della transazione con session.commit
rende la loro
memorizzazione definitiva.La classe Bakelite
e' aggiunta
in maniera automatica allo schema del database quando gli oggetti diventano
persistenti. Comunque Objectivity contiene dei tools per creare esplicitamente
il modello dei dati.
IObject
che permettono di accedere/modificare le loro proprieta'.
Come si vede,questi metodi, prevedono per ogni oggetto persistente un oggetto
locale che ha la stessa struttura (in questo caso getPathInfo()
- ritorna informazioni sugli identificatori
che permettono di accedere all'oggetto in questione.
getAttrs()
- ritorna una copia locale dell'oggetto.
setAttrs(Record r)
-permette di modificare una qualsiasi
proprieta' dell'oggetto attraverso una copia locale.
BakeliteData
)
che viaggia tra client e server.
Applicazione 8:Interroga il Data Base Objectivity per trovare l'oggetto Bakelite
con un certo valore di id
S
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.*;
public interface Compute extends Remote {
/* java.util.Vector getLocalBakelite (int wheel, int id) throws RemoteException; */
double getLocalBakelite (int wheel, int id) throws RemoteException;
}
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
import java.io.*;
import java.rmi.registry.*;
import com.objy.db.*;
import com.objy.db.app.*;
public class ComputeEngine extends UnicastRemoteObject implements Compute
{
private String id;
private int count = 0;
Session session;
String db_name;
Connection conn;
public ComputeEngine(String _id) throws RemoteException {
super();
id = _id;
}
/* returns all the local chambers, including those in the replicated databases */
public double getLocalBakelite(int wheel, int id) throws RemoteException {
double dato1 = 0.0;
java.util.Vector result = new java.util.Vector();
System.out.println("Proviamo a connetterci");
try {
conn = Connection.open("f:\\Prova\\RPC", oo.openReadWrite);
conn.setThreadPolicy(oo.THREAD_POLICY_UNRESTRICTED);
session = new Session();
System.out.println("Connessione riuscita e sessione aperta");
session.setOpenMode(oo.openReadOnly);
session.setMrowMode(oo.MROW);
session.begin();
System.out.println("Dopo la connessione");
conn.getSchemaPolicy().setChangeClassAllowed(false);
conn.getSchemaPolicy().setFieldAccessControlEnforced(false);
conn.setSchemaClassName("Wheel", "Wheel");
conn.setSchemaClassName("Bakelite", "Bakelite");
} catch (DatabaseNotFoundException exception) {
System.err.println("Federated database \"RPC\" not found.");
System.exit(1);
} catch (DatabaseOpenException exception) {
System.err.println("Federated database \"RPC\" already open.");
System.exit(1);
}
ooFDObj fd = session.getFD();
ooDBObj db = fd.lookupDB("Bari_rpc");
System.out.println("Proviamo" +fd);
System.out.println("Prima di lookup");
ooContObj cont = db.lookupContainer("Wheel0");
System.out.println("Dopo lookup " +cont);
Iterator itr = cont.scan("Bakelite","id ==" +id);
while (itr.hasMoreElements()) {
Bakelite bak = (Bakelite) itr.nextElement();
System.out.println(bak.getid() + " " + bak.getcodice() + " " + bak.getdato1());
dato1 = bak.getdato1();
}
return dato1;
}
}
import java.rmi.*;
import java.rmi.server.*;
public class Server
{
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Compute engine1 = new ComputeEngine("32");
Naming.rebind("Compute32",engine1);
System.out.println("ComputeEngine bound");
} catch (Exception e) {
System.err.println("ComputeEngine exception: " + e.getMessage());
e.printStackTrace();
}
}
}
import java.rmi.*;
import java.util.*;
public class Client {
public static void main (String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//"+args[0]+"/"+args[1];
Compute comp = (Compute) Naming.lookup(name);
/* java.util.Vector result = comp.getLocalBakelite(0, 20); */
double dato1 = comp.getLocalBakelite(0, 20);
System.out.println("Il valore cercato e' " + dato1);
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
}
Ecco la sequenza completa di operazioni:
Il metodo java TinyHttpd 8000 &
rmiregistry &
startserver.sh
se non si e' sullo
stesso computer della prova precedente.
sh startserver.sh &
java Client cms1.cern.ch Compute32
scan
dell'oggetto container puo' essere usato per
ottenere un iteratore che ci permette di accedere a tutti gli oggetti
del contenitore che verificano una condizione data.
Objectivity/DB permette anche la memorizzazione di questi indici che permettono
di accellerare l'accesso al database per domande molto frequenti.
Applicazione 9:Fatti inviare dal data base una copia di un'oggetto, modifica alcuni valori e rimandalo indietro per aggiornare
l'oggetto nel database
S
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.*;
public interface Compute2 extends Remote {
void setLocalBakelite (int wheel, int id, Record r) throws RemoteException;
Record getLocalBakelite (int wheel, int id) throws RemoteException;
}
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
import java.io.*;
import java.rmi.registry.*;
import com.objy.db.*;
import com.objy.db.app.*;
public class Server2 extends UnicastRemoteObject implements Compute2
{
private String id;
private int count = 0;
Session session;
String db_name;
Connection conn;
public Server2() throws RemoteException {
super();
System.out.println("Proviamo a connetterci");
try {
conn = Connection.open("RPC1", oo.openReadWrite);
conn.setThreadPolicy(oo.THREAD_POLICY_UNRESTRICTED);
session = new Session();
System.out.println("Connessione riuscita e sessione aperta");
// session.setOpenMode(oo.openReadOnly);
// session.setMrowMode(oo.MROW);
System.out.println("Dopo la connessione");
conn.getSchemaPolicy().setChangeClassAllowed(false);
conn.getSchemaPolicy().setFieldAccessControlEnforced(false);
conn.setSchemaClassName("Wheel", "Wheel");
conn.setSchemaClassName("Bakelite", "Bakelite");
} catch (DatabaseNotFoundException exception) {
System.err.println("Federated database \"RPC\" not found.");
System.exit(1);
} catch (DatabaseOpenException exception) {
System.err.println("Federated database \"RPC\" already open.");
System.exit(1);
}
}
public Record getLocalBakelite(int wheel, int id) throws RemoteException {
Record d = null;
java.util.Vector result = new java.util.Vector();
session.begin();
ooFDObj fd = session.getFD();
ooDBObj db = fd.lookupDB("RPCdata");
System.out.println("Proviamo" +fd);
System.out.println("Prima di lookup");
ooContObj cont = db.lookupContainer("Wheel0");
System.out.println("Dopo lookup " +cont);
Iterator itr = cont.scan("Bakelite","id ==" +id);
while (itr.hasMoreElements()) {
Bakelite bak = (Bakelite) itr.nextElement();
System.out.println(bak.getid() + " " + bak.getcodice() + " " + bak.getdato1());
d = bak.getAttrs();
}
session.commit();
return d;
}
public void setLocalBakelite(int wheel, int id, Record r) throws RemoteException {
java.util.Vector result = new java.util.Vector();
session.begin();
ooFDObj fd = session.getFD();
ooDBObj db = fd.lookupDB("RPCdata");
System.out.println("Proviamo" +fd);
System.out.println("Prima di lookup");
ooContObj cont = db.lookupContainer("Wheel0");
System.out.println("Dopo lookup " +cont);
Iterator itr = cont.scan("Bakelite","id ==" +id);
while (itr.hasMoreElements()) {
Bakelite bak = (Bakelite) itr.nextElement();
System.out.println(bak.getid() + " " + bak.getcodice() + " " + bak.getdato1());
bak.setAttrs(r);
}
session.commit();
}
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Server2 engine1 = new Server2();
Naming.rebind("Compute32",engine1);
System.out.println("Server ready");
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
}
} catch (Exception e) {
System.err.println("Server error: " + e.getMessage());
e.printStackTrace();
}
}
}
ComputeEngine
e Server
sono state
riunite in un'unica classe Server2
, in quanto ora abbiamo
bisogno di un'unico oggetto che all'inizio si connette al data base e poi
si mette in attesa di richieste.
getLocalBakelite
prevede l'invio di una copia
dei dati dell'oggetto Bakelite
cercato usando l'oggetto locale
BakeliteData
.
import java.rmi.*;
import java.util.*;
public class Client2 {
public static void main (String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//"+args[0]+"/"+args[1];
Compute2 comp = (Compute2) Naming.lookup(name);
BakeliteData d =(BakeliteData) comp.getLocalBakelite(0, 20);
System.out.println("Il valore cercato e' " + d.dato1);
d.dato1 = 1111.11111;
comp.setLocalBakelite(0,20,d);
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
}
Applet10:
Come il precedente, ma ora rendendo la cosa possibile con un'interfaccia
grafica all'interno di un'applet.
S
import java.rmi.*;
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
public class ClientApplet1 extends Applet implements ActionListener{
BakeliteData d ;
Compute2 comp;
TextField idt,codicet,dato1t,dato2t,dato3t;
Button b1,b2;
public void init(){
add(idt = new TextField());
add(codicet = new TextField());
add(dato1t = new TextField());
add(dato2t = new TextField());
add(dato3t = new TextField());
add(b1 = new Button("Get new object"));
add(b2 = new Button("Change object"));
b1.addActionListener(this);
b2.addActionListener(this);
if (System.getSecurityManager()==null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//cms2.cern.ch/Compute32";
comp = (Compute2) Naming.lookup(name);
d =(BakeliteData) comp.getLocalBakelite(0, 20);
idt.setText(Integer.toString(d.id));
codicet.setText(d.codice);
dato1t.setText(Double.toString(d.dato1));
dato2t.setText(Double.toString(d.dato2));
dato3t.setText(Double.toString(d.dato3));
System.out.println("Il valore cercato e' " + d.dato1);
// d.dato1 = 1111.11111;
// comp.setLocalBakelite(0,20,d);
System.out.println("Bakelite is "+d.id+" "+d.codice+" "+d.dato1);
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent ev){
if (ev.getSource() == b1){
try {
d =(BakeliteData) comp.getLocalBakelite(0, Integer.parseInt(idt.getText()));
idt.setText(Integer.toString(d.id));
codicet.setText(d.codice);
dato1t.setText(Double.toString(d.dato1));
dato2t.setText(Double.toString(d.dato2));
dato3t.setText(Double.toString(d.dato3));
repaint();
} catch (Exception e) {
System.err.println("Exception in RMI: "+e.getMessage());
e.printStackTrace();
}
}
if (ev.getSource() == b2){
try {
d.id = Integer.parseInt(idt.getText());
d.codice = codicet.getText();
d.dato1 = Double.valueOf(dato1t.getText()).doubleValue();
d.dato2 = Double.valueOf(dato2t.getText()).doubleValue();
d.dato3 = Double.valueOf(dato3t.getText()).doubleValue();
comp.setLocalBakelite(0,d.id,d);
} catch (Exception e1) {
System.err.println("Exception in RMI: "+e1.getMessage());
e1.printStackTrace();
}
}
}
}
Prova l'applet qui.
java TinyHttpd 8000
Interfacciamento a data base relazionali SQL con XML e JAXP
L'XML e' uno standard che permette di creare nuovi linguaggi di marcatura. In pratica ognuno puo' crearsi
i comandi tipo HTML
che piu' rispondono a descrivere un certo tipo di informazione.
Ad esempio potremmo inventare questi comandi per descrivere le schede di una biblioteca.
In gergo si dice che l'XML permette di rappresentare informazione strutturata.
Esso dovrebbe servire a realizzare il sogno del creatore del Web, Tim Berners Lee, di rendere tutta l'informazione online classificabile, permettendo di
rappresentare anche l'informazione ora non HTML in un formato classificabile
e rendendo possibile la scrittura di documenti che si autodescrivono.
Questo e' il sogno di realizzare il cosiddetto Web semantico ovvero
tutta l'informazione online come un'enorme database in un'unico formato
,l'XML appunto,facilmente accessibile
ai programmi di computer.
Applicazione 11:
Scrivete il programma "CiaoATutti" dell'XML, cioe' un programma che non fa niente, se non indicare quando i vari comandi XML iniziano e quando finiscono, e il
contenuto tra tag di apertura e chiusura. Applicatelo al file che descrive
le schede di una biblioteca.
S
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
public class Loadxml extends DefaultHandler
{
public static void main(String argv[])
{
if (argv.length != 1) {
System.err.println("Usage: cmd filename");
System.exit(1);
}
// Use an instance of ourselves as the SAX event handler
DefaultHandler handler = new Loadxml();
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF8");
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
} catch (Throwable t) {
t.printStackTrace();
}
System.exit(0);
}
static private Writer out;
public void startDocument()
throws SAXException
{
System.out.println("Start Document");
}
public void endDocument()
throws SAXException
{
System.out.println("End Document");
}
public void startElement(String namespaceURI,
String lName, // local name
String qName, // qualified name
Attributes attrs)
throws SAXException
{
String name = lName;
if ("".equals(name)) name = qName;
System.out.println("Start Element " + name);
}
public void endElement(String namespaceURI,
String sName, // simple name
String qName // qualified name
)
throws SAXException
{
String name = sName;
if ("".equals(name)) name = qName;
System.out.println("End Element " + name);
}
public void characters(char buf[], int offset, int len)
throws SAXException
{
String s = new String(buf, offset, len);
System.out.println("Contenuto comando " + s);
}
}
DefaultHandler
startDocument, endDocument, startElement, endElement e characters
permettono di "intercettare" i comandi XML.
Applicazione 12:
Modificate l'applicazione 1 in modo da esportare i dati della tabella Persone
in formato xml in un file Persone.xml
.
S
// You need to import the java.sql package to use JDBC
import java.sql.*;
import java.io.*;
class Persone
{
public static void main (String args [])throws IOException
{
try {
// Load the Mysql JDBC driver
try {
Class.forName("org.gjt.mm.mysql.Driver");
} catch (ClassNotFoundException e) {
System.out.println ("Mysql device driver does not exist");
System.exit(1);
}
BufferedWriter myOutput;
File outputFile = new File("Persone.xml");
myOutput = new BufferedWriter(new FileWriter(outputFile));
myOutput.write("\n");
myOutput.write("
Ecco il risultato
Applicazione 13:
Un database Oracle permette l'interrogazione sulla porta 3615 attraverso XML.
Scrivete un programma che legge la query (SELECT) in XML dal file input.xml
e scrive il risultato nel file output.xml
S
import java.io.*;
import java.net.*;
public class Readxml {
public static void main(String[] args) throws IOException {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
BufferedWriter myOutput;
String inputLine;
String line;
BufferedReader data;
data = new BufferedReader(new FileReader(new File("input.xml")));
myOutput = new BufferedWriter(new FileWriter("output.xml"));
try {
echoSocket = new Socket("cmstrkdb.in2p3.fr",3615);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: "+args[0]);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: "+args[0]);
System.exit(1);
}
while ((line = data.readLine()) != null) {
out.println(line);
}
while ( (inputLine=in.readLine())!=null) {
myOutput.write(inputLine+"\n");
}
out.close();
in.close();
myOutput.close();
echoSocket.close();
}
}
Ecco il risultato in uscita con la seguente
query
Applicazione 14:
Scrivete un'applicazione grafica che processa il file ricevuto dal database
Oracle e fa un display di tutte le strip morte per i circa 800 sensori.
S
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
public class Displayxml extends DefaultHandler
{
String nomecomando;
int nr = 0;
JPanel border=new JPanel(new BorderLayout());
JFrame frame = new JFrame ("Bad strips display");
Display disegno = new Display();
JScrollPane base;
static Displayxml lx;
public Displayxml(){
lx = this;
}
public static void main(String argv[])
{
if (argv.length != 1) {
System.err.println("Usage: cmd filename");
System.exit(1);
}
// Use an instance of ourselves as the SAX event handler
DefaultHandler handler = new Displayxml();
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF8");
lx.frame.setContentPane(lx.border);
lx.disegno.setPreferredSize( new Dimension(768,800));
lx.base=new JScrollPane(lx.disegno,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
lx.base.setBackground(Color.white);
lx.border.add(lx.base, BorderLayout.CENTER);
lx.frame.pack();
lx.frame.show();
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
} catch (Throwable t) {
t.printStackTrace();
}
// System.exit(0);
}
static private Writer out;
public void startDocument()
throws SAXException
{
System.out.println("Start Document");
}
public void endDocument()
throws SAXException
{
System.out.println("Numero sensori = "+nr);
}
public void startElement(String namespaceURI,
String lName, // local name
String qName, // qualified name
Attributes attrs)
throws SAXException
{
String name = lName;
if ("".equals(name)) name = qName;
nomecomando = name;
if(nomecomando.equals("row"))nr++;
}
public void endElement(String namespaceURI,
String sName, // simple name
String qName // qualified name
)
throws SAXException
{
String name = sName;
if ("".equals(name)) name = qName;
nomecomando=" ";
}
public void characters(char buf[], int offset, int len)
throws SAXException
{
String s = new String(buf, offset, len);
if(nomecomando.equals("value")&& !(s.equals("null")||s.equals("NULL")))
{
StringTokenizer st = new StringTokenizer(s);
while(st.hasMoreTokens()){
lx.disegno.disegnastrip(nr,new Integer(st.nextToken()).intValue());}
}
}
class Display extends JPanel{
int xstrip,ystrip;
public void disegnastrip(int x,int y){xstrip=x;ystrip=y;repaint();}
public void paintComponent(Graphics g){
g.setColor(Color.black);
g.fillRect(xstrip,ystrip,1,1);
}
}
}
characters
quando viene processato il
contenuto del comando XML VALUE.
startElement e stopElement
sono stati modificati per sapere
nel resto del programma quale comando XML viene processato.
Applicazione 15:Scrivete un programma che mostra
le notizie presenti in un documento in formato RSS.
S
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
public class Displaynews extends DefaultHandler
{
String nomecomando;
ArrayList titoli;
int nr = 0;
JPanel border=new JPanel(new BorderLayout());
JFrame frame = new JFrame ("Bad strips display");
Display disegno = new Display();
JScrollPane base;
static Displaynews lx;
Image o;
Graphics og;
public Displaynews(){
lx = this;
titoli = new ArrayList();
}
public static void main(String argv[])
{
if (argv.length != 1) {
System.err.println("Usage: cmd filename");
System.exit(1);
}
// Use an instance of ourselves as the SAX event handler
DefaultHandler handler = new Displaynews();
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF8");
lx.border.setPreferredSize( new Dimension(400,400));
lx.frame.setContentPane(lx.border);
lx.disegno.setPreferredSize( new Dimension(768,800));
lx.base=new JScrollPane(lx.disegno,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
lx.base.setBackground(Color.white);
lx.border.add(lx.base, BorderLayout.CENTER);
lx.frame.pack();
lx.frame.show();
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
} catch (Throwable t) {
t.printStackTrace();
}
// System.exit(0);
}
static private Writer out;
public void startDocument()
throws SAXException
{
System.out.println("Start Document");
}
public void endDocument()
throws SAXException
{
System.out.println("Numero notizie = "+nr);
}
public void startElement(String namespaceURI,
String lName, // local name
String qName, // qualified name
Attributes attrs)
throws SAXException
{
String name = lName;
if ("".equals(name)) name = qName;
nomecomando = name;
if(nomecomando.equals("item"))nr++;
}
public void endElement(String namespaceURI,
String sName, // simple name
String qName // qualified name
)
throws SAXException
{
String name = sName;
if ("".equals(name)) name = qName;
nomecomando=" ";
}
public void characters(char buf[], int offset, int len)
throws SAXException
{
String s = new String(buf, offset, len);
System.out.println(nomecomando+" "+s);
if(nomecomando.equals("title")&&nr>0)
{
lx.disegno.scrivinotizia(nr,s);}
}
class Display extends JPanel{
int ystrip;
String s;
public void scrivinotizia(int y,String s1){ystrip=y;s=s1;
if(s!=null && s.length() != 0)titoli.add(s);repaint();}
public void paintComponent(Graphics g){
if(lx.o==null){
lx.o = lx.frame.createImage(lx.disegno.size().width,lx.disegno.size().height);
lx.og = lx.o.getGraphics();
lx.og.setColor(Color.white);
lx.og.fillRect(0,0,disegno.size().width,disegno.size().height);}
lx.og.setColor(Color.black);
if(titoli!=null) if(titoli.size()>0)for(int i=0;i < titoli.size();i++){
String s2=(String)titoli.get(i);
lx.og.drawString(s2,5,i*20+20);
System.out.println("notizia "+i +" "+s2);
}
g.drawImage(lx.o,0,0,this);
}
}
}
Ora potete considerare tutto il Web come un'enorme database e scrivere
programmi che vi filtrano centinaia di siti di notizie o dati selezionando quelli
piu' interessanti per voi:proprio quello che il Web semantico si propone
di raggiungere.
INDIETRO a Imparate Java in una settimana
INDIETRO a Seminario su Java
Maintained by Giuseppe Zito:
info@zitogiuseppe.com
Ultimo aggiornamento: