Lezione n.6 LPR Informatica Applicata Serializzazione...
Transcript of Lezione n.6 LPR Informatica Applicata Serializzazione...
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 1
Lezione n.6LPR Informatica Applicata
Serializzazione JAVA(alcuni lucidi sono ripresi da appunti di
Leonardo Puleggi)
Università degli Studi di Pisa Dipartimento di Informatica
28/03/2013Laura Ricci
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 2
SERIALIZZAZIONE
• in JAVA, ogni entità è rappresentata come un oggetto; se due entità vogliono comunicare si devono scambiare oggetti
• serializzazione: meccanismo che permette di salvare un oggetto o un grafo di oggetti su uno stream di byte che successivamente può essere salvato su un file inviato sulla rete
• deserializzazione: processo inverso, permette di ricostruire l'oggetto/il grafo di oggetti dallo stream di byte
• La serializzazione si basa sulla possibilità di scrivere lo stato di un oggetto in una forma sequenziale, sufficiente per ricostruire l'oggetto quando viene riletto.
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 3
SERIALIZZAZIONE
La serializzazione di oggetti viene usata in diversi contesti:
inviare oggetti su uno stream che rappresenta una connessioneTCP
flattening di oggetti: trasformare un oggetto in un array di byte. Utilizzato per costruire pacchetti UDP.
inviare oggetti che sono parametri di metodi invocati via RMI
fornire un meccanismo di persistenza ai programmi, consentendo l'archiviazione di un oggetto.
● esempio: un programma che realizza una rubrica telefonica o un'agenda.
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 4
JAVA: LA SERIALIZZAZIONE
• Meccanismo standard offerto da JAVA Le classi ObjectInputStream e ObjectOutputStream definiscono
streams (basati su streams di byte) su cui si possono leggere e scrivere oggetti.
per rendere un oggetto “persistente”, l'oggetto deve implementare l'interfaccia Serializable o ereditarne una implementazione dalla gerarchia di oggetti.
l'oggetto e tutti i suoi componenti debbono essere serializzabili non tutti gli oggetti possono essere serializzati.
Es: oggetti del sistema quali Thread, OutputStream e Socket non possono essere serializzate
• Altri meccanismi offerti da JAVA personalizzare il meccanismo di default (interfaccia Serializable) creare un proprio protocollo (classe Externalizable)
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 5
JAVA: LA SERIALIZZAZIONE
In rosso le parti relative alla serializzazione
import java.io.Serializable;
import java.util.Date;import java.util.Calendar;
public class PersistentTime implements Serializable { private static final long serialversionUId=1; private Date time; public PersistentTime() {time = Calendar.getInstance().getTime(); } public Date getTime() {return time; }}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 6
JAVA: LA SERIALIZZAZIONE
import java.io.*;public class FlettenTime {public static void main(String [] args) {String filename = "time.ser"; if(args.length > 0) { filename = args[0]; } PersistentTime time = new PersistentTime(); FileOutputStream fos = null; ObjectOutputStream out = null; try
{ fos = new FileOutputStream(filename); out = new ObjectOutputStream(fos); out.writeObject(time); out.close(); } catch(IOException ex) {ex.printStackTrace();}}}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 7
JAVA: LA SERIALIZZAZIONEpublic class InflateTime{public static void main(String [] args) {String filename = "time.ser"; if(args.length > 0) {filename = args[0]; } PersistentTime time = null; FileInputStream fis = null; ObjectInputStream in = null; try {fis = new FileInputStream(filename); in = new ObjectInputStream(fis); time = (PersistentTime)in.readObject(); in.close(); } catch(IOException ex){ ex.printStackTrace(); } catch(ClassNotFoundException ex) {ex.printStackTrace();}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 8
JAVA: LA SERIALIZZAZIONE
// print out restored time System.out.println("Flattened time: " + time.getTime()); System.out.println(); // print out the current time System.out.println("Current time: "+ Calendar.getInstance().getTime());}}Output ottenuto:Flattened time: Mon Mar 12 19:11:55 CET 2012Current time: Mon Mar 12 19:16:24 CET 2012
ClassNotFoundException: l'applicazione tenta di caricare una classe, ma non trova nessuna definizione di una classe con quel nome
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 9
JAVA: LA SERIALIZZAZIONE
• La versione viene utilizzata in fase di deserializzazione per verificare che le classi utilizzate da chi ha serializzato l'oggetto e da chi lo sta deserializzando siano compatibili (vedere second aparte della lezione)
• Il metodo ObjectInputStream.readObject() legge la sequenza di bytes memorizzati in precedenza e crea un oggetto che è l'esatta replica di quello originale
• Poichè readObject può leggere qualsiasi tipo di oggetto, è necessario effettuare un cast al tipo corretto dell'oggetto
• Il file con la specifica della classe deve essere accessibile quando si ricostruisce l'oggetto, altrimenti viene sollevata una ClassNotFoundException
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 10
SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
import java.io.Serializable;import java.util.*;
public class Padre implements Serializable {private static final long serialVersionUID = 1L;private String nome;private String cognome;private Collection<Figlio> figli;
public Padre(String nome,String cognome){this.nome=nome;this.cognome=cognome;figli=new ArrayList<Figlio>();
}
public void aggiungiFiglio(Figlio f){figli.add(f); }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 11
SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
public String toString(){StringBuilder temp=new StringBuilder("Padre");temp.append("\n");temp.append("nome: ");temp.append(this.nome);temp.append("\n");temp.append("cognome: ");temp.append(this.cognome);emp.append("\n");temp.append("Figli: ");temp.append(figli.toString());
return temp.toString();}}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 12
SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
import java.io.Serializable;
public class Figlio implements Serializable{private static final long serialVersionUID = 1L;
private String nome;private String cognome;
public Figlio(String nome,String cognome){ this.nome=nome; this.cognome=cognome; }
public String toString(){ return "nome: "+nome+" cognome: "+cognome; }}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 13
SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
public class SerializzaPadre {
public static void main(String[] args) {Figlio a=new Figlio("mario","rossi");Figlio b=new Figlio("maria","rossi");
Padre p=new Padre("giovanni","rosso"); p.aggiungiFiglio(a); p.aggiungiFiglio(b); ObjectOutputStream output=null; try{ output=new ObjectOutputStream(new FileOutputStream("dati.dat")); } catch (FileNotFoundException e) { System.out.println("Impossibile trovare il file "); e.printStackTrace(); System.exit(1); } catch(IOException ioe){ System.out.println("Errore IO"); ioe.printStackTrace(); System.exit(1); }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 14
SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
try { output.writeObject(p); }catch (IOException e1) { System.out.println("Impossibile serializzare l'oggetto " + p); e1.printStackTrace(); System.exit(1); } try { output.close(); } catch (IOException e2) { System.out.println("Impossibile chiudere lo stream "); e2.printStackTrace(); }System.out.println("Serializzazione completata.");
}}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 15
DESERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
import java.io.*;
public class DeSerializzaPadre {public static void main(String[] args) {ObjectInputStream ois = null;try { ois = new ObjectInputStream(new FileInputStream("dati.dat"));} catch (FileNotFoundException e) { System.out.println("Impossibile trovare il file "); e.printStackTrace(); System.exit(1);} catch (IOException e) { System.out.println("Errore nella creazione dello stream "); e.printStackTrace(); System.exit(1);}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 16
DESERIALIZZAZIONE: GRAFO DEI RIFERIMENTI
Padre p=null;try { p = (Padre) ois.readObject();} catch (IOException e1) { System.out.println("Errore nella creazione dello stream "); e1.printStackTrace(); System.exit(1); } catch (ClassNotFoundException e1) { System.out.println("Impossibile trovare la classe"); e1.printStackTrace(); System.exit(1); }System.out.println(p.toString());}}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 17
SERIALIZZAZIONE
• L'esempio precedente mostra che si possono serializzare/deserializzare oggetti che al loro interno fanno riferimento ad altri oggetti
• L'implementazione serializza transitivamente tutti gli oggetti riferiti
• Se però uno degli oggetti riferiti non è serializzabile, viene sollevata una NotSerializableException
• E' possibile non includere il valore di alcuni attributi nell'oggetto serializzato, mediante l'utilizzo della parola chiave transient
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 18
SERIALIZZAZIONE
import java.io.Serializable;import java.util.*;
public class Padre implements Serializable {private static final long serialVersionUID = 1L;
private String nome;private String cognome;transient private Collection<Figlio> figli;….....
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 19
SERIALIZZAZIONE
• l'attributo transient inserito nell'esempio precedente indica che non si vuole serializzare l'attributo Figli della classe Padre
• la parola chiave transient limita la visita nell'albero dei riferimenti
• tutti gli altri attributi vengono salvati
• se si esegue la serializzazione e quindi la deserializzazione, il campo figli nell'oggetto deserializzato, risulta uguale a null
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 20
LA SERIALIZZAZIONE STEP BY STEP
Cosa avviene quando un oggetto viene serializzato? Si registrano sullo stream:• i “magic data”
STREAM_MAGIC = “acde” STREAM_VERSION = versione della JVM
• I metadati che descrivono la classe associata alla istanza dell'oggetto serializzato (La classe Padre nell'esempio precedente) La descrizione include il nome della classe, il serialVersionUID della
classe, il numero di campi, altri flag.• I metadati di eventuali superclassi, fino a raggiungere java.lang.Object• I valori associati all'oggetto istanza della classe, partendo dalla super
classe top most• I dati degli oggetti eventualmente riferiti dall'oggetto istanza della
classe, iniziando dai metadati e poi registrando i valori. (Le istanze della classe Figlio, nell'esempio precedente).
• Non si registrano i metodi della classe
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 21
LA SERIALIZZAZIONE STEP BY STEP
• Consideriamo la classe SimpleClass con campi firstName,
lastName,
weight
Location
• L'oggetto istanza della classe contiene i campi {"Brad","Pitt",180.5, {49.345, 67.567}}
• A fianco:risultato della serializzazione
• Notare: per la memorizzazione di un oggetto di 20 bytes utilizzati circa 220 bytes
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 22
LA SERIALIZZAZIONE: “UNDER THE HOOD”
Meccanismi implementati dalla JVM che è importante conoscere per utilizzare la serializzazione in modo corretto:
Caching
Controllo delle versioni
Deadlock
Performance
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 23
SERIALIZATION CACHE
public class BigData { private static final long TERA_BYTE = 1024L * 1024 * 1024 * 1024; public static void main(String[] args) throws IOException { long bytesWritten = 0; byte[] data = new byte[100 * 1024 * 1024]; ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("bigdata.bin") ) ); long time = System.currentTimeMillis();
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 24
SERIALIZATION CACHEfor (int i = 0; i < 10 * 1024 * 1024; i++) { out.writeObject(data); bytesWritten += data.length; } out.writeObject(null); out.close(); time = System.currentTimeMillis() - time; System.out.printf("Wrote %d TB%n", bytesWritten / TERA_BYTE); System.out.println("time = " + time); } }Wrote 1000 TB Time = 3693
Ma la dimensione del file bigdata.bin è solo di 150 M. Come è possibile???
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 25
SERIALIZATION CACHE
• Ogni qual volta un oggetto viene serializzato e inviato ad una ObjectOutputStream, la sua identità viene memorizzata in una “identity hash table”
• Se l'oggetto viene scritto nuovamente sull'OutputStream, l'oggetto stesso non viene nuovamente serializzato, ma viene memorizzato un puntatore all'oggetto serializzato in precedenza scopo: minimizzazione delle scritture e risoluzione di relazioni
circolari tra oggetti• Comportamento analogo quando si legge da uno stream: l'oggetto letto
viene memorizzato in una “identity hash table”, la prima volta Letture future fanno riferimento allo stesso oggetto
• Possibili inconsistenze quando lo stato dell'oggetto viene modificato La modifica viene persa sull'ObjectOutputStream, perchè non viene
aggiornato lo stato
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 26
SERIALIZZAZIONE: BUFFERIZZAZIONE
Un esempio che dimostra i problemi che può dare un serialization cache:
import java.io.*; public class MyObject implements Serializable{ private static final long serialVersionUID = 1L; private int x; public MyObject(){ }; public void set( int x) {this.x=x;} public int get() {return x;}; }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 27
SERIALIZZAZIONE: BUFFERIZZAZIONE
import java.io.*; import java.net.*;public class SerializationClient { public static void main (String Args [] ) throws Exception { Socket s= new Socket("localHost",4000); ObjectOutputStream out = new ObjectOutputStream (s.getOutputStream());
MyObject myobj = new MyObject(); myobj.set(100); out.writeObject(myobj); myobj.set(200); out.writeObject(myobj); } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 28
SERIALIZZAZIONE: BUFFERIZZAZIONE
import java.net.*;import java.io.*;public class SerializableServer { public static void main(String args[]) throws Exception {ServerSocket ss = new ServerSocket(4000); Socket s=ss.accept(); ObjectInputStream ois= new ObjectInputStream (s.getInputStream()); MyObject myobj = (MyObject)ois.readObject(); System.out.println(myobj.get()); myobj = (MyObject)ois.readObject(); System.out.println(myobj.get());
}} OUTPUT 100 100
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 29
SERIALIZZAZIONE: CACHING
import java.io.*;
import java.util.Arrays;
public class FillCache {
public static void main(String[] args) throws IOException {
byte[] data = new byte[10 * 1024 * 1024];
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream("smalldata.bin") ) );
for (int i = -128; i < 128; i++) {
Arrays.fill(data, (byte) i);
out.writeObject(data);
}
out.writeObject(null);
out.close();
} }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 30
SERIALIZZAZIONE: CACHING
import java.io.*;
public class ReadCache {
public static void main(String[] args) throws Exception {
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream("smalldata.bin")
)
);
byte[] data;
while ((data = (byte[]) in.readObject()) != null) {
System.out.println(data[0]); }
in.close(); } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 31
SERIALIZZAZIONE: CACHING
• La stampa ottenuta: -128, -128, -128, …..
• Perdita di valori dovuta al meccanismo di serializzazione
• Al momento della deserializzazione, si legge il vettore contenente 128 la prima volta e si memorizza nella “identity hash table”
• Quando legge un puntatore all'oggetto, si ricerca il valore dell'oggetto dalla cache locale
• Il meccanismo di serializzazione ignora se l'oggetto è stato modificato
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 32
SERIALIZZAZIONE: CACHING
import java.io.*;
import java.util.Arrays;
public class FillCache1 {
public static void main(String[] args) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream( new FileOutputStream("verylargedata.bin")));
for (int i = -128; i < 128; i++) {
byte[] data = new byte[10 * 1024 * 1024];
Arrays.fill(data, (byte) i);
out.writeObject(data);
}
out.writeObject(null);
out.close(); } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 33
SERIALIZZAZIONE: CACHING
Risultato ottenutoException in thread "main" java.lang.OutOfMemoryError: Java heap spaceat FillCache1.main(FillCache1.java:13)
Il file generato è di dimensioni molto grandi
Ogni volta che un oggetto viene scritto sullo stream, esso viene posto nella “identity hash table”
Rimane nella table finchè non viene effettuata una reset sullo stream
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 34
SERIALIZZAZIONE: CACHING
import java.io.*;
import java.util.Arrays;
public class FillCache2 {
public static void main(String[] args) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream("verylargedata.bin")) );
byte[] data = new byte[10 * 1024 * 1024];
for (int i = -128; i < 128; i++) {
Arrays.fill(data, (byte) i);
out.writeObject(data);
out.reset(); }
out.writeObject(null);
out.close(); } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 35
SERIALIZZAZIONE: CACHING
• La stampa ottenuta -128, -127, -126, …
• Il programma non segnala un OutOfMemory Error
• La reset effettua il flush della tabella dopo ogni operazione di scrittura
• Ad ogni write un nuovo oggetto sullo stream
• Svantaggio: nessuna ottimizzazione, tutti i valori(anche i campi che non hanno cambiato valore) eliminati dalla cache
• Infatti il programma richiede molto tempo per terminare
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 36
IL CONTROLLO DELLE VERSIONI
• supponiamo di creare una classe i cui oggetti siano serializzabili
• serializziamo un oggetto istanza di quella classe
• problema: se cambio la specifica della classe, possono le istanze serializzate secondo la vecchia specifica essere deserializzate come istanze della nuova classe? in generale questo non è possibile
• meccanismo di controllo delle versioni ad ogni classe serializzabile viene attribuito un identificatore unico, il SerialVersionUID
Tale identificatore viene rigenerato ogni volta che viene modificata la classe
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 37
IL CONTROLLO DELLE VERSIONI
• Il serialVersionUID viene generato a partire dal codice della classe
• Modificando il codice si modifica il serialVersionUID
• Generato al momento di una serializzazione/deserializzazione
• Quando deserializzo, se ho modificato il codice, la deserializzazione fallisce si tenta di rileggere l'oggetto, la ricostruzione dell'oggetto fallisce
e viene sollevata una java.io.InvalidClassException
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 38
IL CONTROLLO DELLE VERSIONI
• SerialVersionUID utilizzato in fase di deserializzazione per verificare che il mittente ed il destinatario di un oggetto serializzato fanno riferimento a classi compatibili
• Le classi in realtà potrebbero essere compatibili
• Possibile, in questo caso, specificare esplicitamente il serialVersionUID e forzarlo uguale nelle due versioni
• Specifica serialVersionUID: il valore può essere qualsiasi valore long
private static final long serialVersionUID = 3487495895819393L;
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 39
IL CONTROLLO DELLE VERSIONI
• Specifica serialVersionUID: il valore può essere qualsiasi valore long private static final long serialVersionUID = 3487495895819393L;
• Il meccanismo di serializzazione controlla se l'utente ha dichiarato esplicitamente un valore per il serialVerisonUID ed, in questo caso, usa questo valore, invece di calcolarlo in modo automatico
• Se in una classe non esiste una dichiarazione esplicita di un serialVersionUID, il meccanismo di serializzazione lo calcola automaticamente
• Dichiarazione esplicita di serialVersionUID: per garantire valori consistenti tra diverse implemetazioni di compilatori JAVA
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 40
CONTROLLO DELLE VERSIONI
• L'identificatore della classe in Eclipse puntando il mouse sul nome di una classe Serializzabile appare
una finestra che permette di generare automaticamente un SerialVersionID
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 41
CONTROLLO DELLE VERSIONI
• L'identificatore della classe in Eclipse puntando il mouse sul nome di una classe Serializzabile appare
una finestra che permette di generare automaticamente un SerialVersionID
utilizzando add generated serial version ID
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 42
OBJECT STREAM: DEADLOCK
• Supponiamo che un'applicazione A1 apra una connessione verso A2 per inviare ad A2 uno stream di oggetti
• A1 associa alla connessione un ObjectOutputStream, mentre A2 associa alla medesima connessione un ObjectInputStream
• Quando A1 crea l'ObjectOutputStream, viene registrato uno sullo stream un header che viene quindi inviato sulla connessione
• Quando A2 crea l' ObjectInputStream– la JVM accede tenta di recuperare l'header dello stream dal socket
associato alla connessione– se l'header non è presente, la JVM si blocca in attesa di ricevere
l'header sul socket– ATTENZIONE: per prevenire situazioni di deadlock occorre porre
attenzione sull'ordine con cui vengono creati gli stream di Input/Output
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 43
OBJECT INPUT/OUTPUT STREAM: DEADLOCK
Se i due partners della connessione eseguono entrambi il seguente frammento
di codice (s è il socket associato alla connessione)ObjectInputStream in = new ObjectInputStream(s.getInputStream( ));ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream( ));si verifica una situazione di deadlock..
Infatti,
• entrambi tentano di leggere l'header dello stream dal socket
• l'header viene generato quando viene viene creato l'ObjectOutputStream
• nessuno dei due è in grado di generare l'ObjectOutputStream,
perchè bloccato
• E' sufficiente invertire l'ordine di creazione degli stream in uno dei partner
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 44
JAVA: LA SERIALIZZAZIONE
• Il meccanismo di default offerto da JAVA è generale e le prestazioni non risultano quindi ottime i riferimenti agli oggetti sono memorizzati nella cache degli oggetti
associata all'OutputStream il garbage collector non può recuperare memoria relativa agli oggetti
scritti sullo stream trade off tra convenienza e semplicità e performance
• Se la performance è un obiettivo primario della applicazione, allora occorre personalizzare il protocollo di serializzazione mediante l'implementazione della interfaccia Externalizable
public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 45
INVIO OGGETTI SU STREAM
Per inviare oggetti su connessioni TCP
• associare i filtri ObjectInputStream/ObjectOutputStream agli stream di bytes associati al socket e restituiti da getInputStream/getOutputStream
• inviare/ricevere degli oggetti sullo/dallo stream avviene mediante scritture/letture sullo stream – writeObject– ReadObject
• i metodi precedenti implementano la serializzazione di un oggetto (discussa nella seconda parte della lezione)
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 46
INVIO DI OGGETTI
import java.io.*;public class Studente implements Serializable {private int matricola;private String nome, cognome, corsoDiLaurea;public Studente(int matricola, String nome, String cognome,
String corsoDiLaurea) {this.matricola = matricola; this.nome = nome; this.cognome = cognome; this.corsoDiLaurea = corsoDiLaurea;}
public int getMatricola () { return matricola; }public String getNome () { return nome; }public String getCognome () { return cognome; }public String getCorsoDiLaurea () { return corsoDiLaurea; } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 47
INVIO DI OGGETTI SU STREMS
import java.io.*; import java.net.*;public class Server {public static void main (String args[]) {try { ServerSocket server = new ServerSocket (3575);
Socket clientsocket = server.accept(); ObjectOutputStream output = new ObjectOutputStream (clientsocket.getOutputStream ());
output.writeObject("<Welcome>");Studente studente = new Studente
(14520,"Mario","Rosso","Informatica");output.writeObject(studente); output.writeObject("<Goodbye>");clientsocket.close();server.close();} catch (Exception e) { } } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 48
COME CHIUDERE UNO STREAM
public class Client { public static void main (String args[ ]) {
try {Socket socket = new Socket ("localhost",3575);
ObjectInputStream input=newObjectInputStream(socket.getInputStream());
String beginMessage = (String) input.readObject();
System.out.println (beginMessage);
Studente studente = (Studente) input.readObject();
System.out.print (studente.getMatricola()+" - ");
System.out.print (studente.getNome()+""+studente.getCognome()+"- ");
System.out.print (studente.getCorsoDiLaurea()+"\n");
String endMessage = (String)input.readObject();
System.out.println (endMessage); socket.close();}
catch (Exception e) { System.out.println (e); } } }
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 49
INVIO DI OGGETTI SU STREAMS
Stampa prodotta lato Client
<Welcome>
14520 - Mario Rossi - Informatica
<Goodbye>
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 50
CHIUSURA DI STREAMS
import java.net.*; import java.io.*; import java.util.*;public class closer {
public static void main(String args[])throws Exception{InetAddress ia = InetAddress.getByName("localhost");Socket out =new Socket(ia,2500);OutputStream outs= out.getOutputStream();ObjectOutputStream oos = new ObjectOutputStream(outs);Date d= new Date();oos.writeObject(d);out.shutdownOutput();}
}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 51
CHIUSURA DI STREAMS
import java.net.*; import java.io.*; import java.util.*;public class server {public static void main (String args[]) throws Exception
{ServerSocket ss = new ServerSocket(2500);Socket s=ss.accept();InputStream is = s.getInputStream();ObjectInputStream ois = new ObjectInputStream(is);boolean go=true;while (go){try{ Date d =(Date) ois.readObject();
System.out.println(d);} catch (IOException e) {System.out.println(e); go=false; }}}}
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 52
ASTA ELETTRONICA
Sviluppare un programma client server per il supporto di un'asta
elettronica. Ogni client possiede un budget massimo B da investire.
Il client può richiedere al server il valore V della migliore offerta
pervenuta fino ad un certo istante e decidere se abbandonare l'asta,
oppure rilanciare. Se il valore ricevuto dal server supera B, l'utente
abbandona l'asta, dopo aver avvertito il server. Altrimenti, il client rilancia,
inviando al server un valore maggiore di V.
Il server invia ai client che lo richiedono il valore della migliore offerta
ricevuta fino ad un certo momento e riceve dai client le richieste di
rilancio. Per ogni richiesta di rilancio, il server notifica al client se tale
offerta può essere accettata (nessuno ha offerto di più nel frattempo),
oppure è rifiutata.
Dipartimento di InformaticaUniversità degli studi di Pisa
JAVASerializzation
Laura Ricci 53
ASTA ELETTRONICA
Il server deve attivare un thread diverso per ogni client che intende
partecipare all'asta.
La comunicazione tra clients e server deve avvenire mediante socket
TCP. Sviluppare due diverse versioni del programma che utilizzino,
rispettivamente:
la serializzazione offerta da JAVA in modo da scambiare oggetti tramite
ule connessione TCP
una codifica testuale dei messaggi spediti tra client e sever