Java: la libreria delle classi • Input/ Output in Java – il package java.io – object serialization • La programmazione di rete – i package java.net e java.rmi 149 Gianpaolo Cugola Approccio generale • La libreria delle classi Java è di una vastità non indifferente Approccio adottato in questo corso: – descrizione delle classi fondamentali… – e delle funzionalità più importanti • Per una descrizione più puntuale si consiglia l’uso della guida ipertestuale alla libreria di classi Gianpaolo Cugola Gianpaolo Cugola 150 Input/Output in Java • Il package java.io – include classi, interfaccie ed eccezioni per la gestione dell’I/ O • Distinguiamo tra due classi di funzionalità: – funzionalità per accedere ad informazioni relative ai file ed alle directory • Esempio: dimensione dei file, elenco dei file contenuti in una directory,... – funzionalità per leggere e scrivere dati 151 Gianpaolo Cugola Classi per l’accesso alle informazioni relative al file system • La classe fondamentale per accedere alle informazioni relative ai file ed alle directory è la classe File • E’ fondamentale tenere presenti i problemi di portabilità del codice: – path • Unix: /bin:/usr/bin:/usr/local/bin • Windows: c:\bin;c:\java\bin – percorso di un file • Unix: /usr/java/bin/javac • Windows: c:\java\bin Gianpaolo Cugola Gianpaolo Cugola 152 La classe File: costanti • public static final String separator – il separatore di file (stringa) • public static final char separatorChar – il separatore di file (carattere) • public static final String pathSeparator – il separatore di path (stringa) • public static final char pathSeparatorChar – il separatore di path (carattere) 153 Gianpaolo Cugola La classe File: esempio 1 import java.io.*; public class Prova { public static void main(String[] arg) { System.out.println(File.separator+" - "+ File.separatorChar+" - "+ File.pathSeparator+" - "+ File.pathSeparatorChar); } } • Output (su Windows): \ - \ - ; - ; Gianpaolo Cugola Gianpaolo Cugola 154 La classe File: costruttori • public File(String path) • public File(String path, String name) • public File(File dir, String name) 155 Gianpaolo Cugola La classe File: metodi principali public String getName() public String getPath() public String getParent() – può ritornare null se non esiste il parent public public public public public public public Gianpaolo Cugola Gianpaolo Cugola boolean exists() boolean canRead() boolean canWrite() boolean isFile() boolean isDirectory () long lastModified() long length() public public public public public public boolean mkdir() boolean mkdirs() boolean renameTo(File dest) String[] list() String[] list(FilenameFilter f) boolean delete() 156 Lettura e scrittura di dati • Distinguiamo tra – classi per l’accesso sequenziale ai dati • di utilizzo generale, non limitate ai file – classi per l’accesso diretto (random) a dati contenuti su file 157 Gianpaolo Cugola Classi per la lettura e la scrittura sequenziale di dati • Il meccanismo di lettura e scrittura sequenziale dei dati è basato sul concetto di stream • Uno stream è un oggetto sul quale è possibile leggere e scrivere dati sequenzialmente • Il package java.io include numerose classi per la gestione di stream Gianpaolo Cugola Gianpaolo Cugola 158 Lettura sequenziale di byte Object (from java.lang) File ObjectInputStream SequenceInputStream DataInputStream InputStream PipedInputStream FileInputStream ByteArrayInputStream FileDescriptor FilterInputStream BufferedInputStream ObjectStreamClass StringBufferInputStream LineNumberInputStream PushBackInputStream 159 Gianpaolo Cugola La classe InputStream • Classe astratta che racchiude tutti i metodi per la lettura da uno stream di byte • Metodi principali: – public void close() – public int available() – public long skip(long n) – public abstract int read() • bloccante; ritorna -1 se si è raggiunta la fine dello stream – public int read(byte b[]) • bloccante; ritorna -1 se si è raggiunta la fine dello stream – public int read(byte b[], int off, int len) • bloccante; ritorna -1 se si è raggiunta la fine dello stream Gianpaolo Cugola Gianpaolo Cugola 160 La classe FileInputStream • Usata per l’accesso sequenziale a file di byte • Ridefinisce i metodi della classe InputStream fornendone una implementazione per i file • Costruttori: – public FileInputStream(String name) – public FileInputStream(File f) – public FileInputStream(FileDescriptor fd) • Principali metodi aggiunti – public final FileDescriptor getFD() 161 Gianpaolo Cugola La classe FileInputStream: un esempio import java.io.*; public class ProvaFile { public static void main(String[] args) { if(args.length!=1) {System.err.println("Usage: ProvaFile <nome file>");System.exit(-1);} File f=new File(args[0]); FileInputStream fis=null; byte[] b; int byteRead; if(!f.exists()) System.err.println("Error: file "+args[0]+ " does not exists"); else if(!f.canRead()) System.err.println("Error: cannot read from file "+args[0]); else { b=new byte[(int)f.length()]; try{ fis=new FileInputStream(f); byteRead=fis.read(b); System.out.println("Bytes read: "+byteRead); } catch(Exception ex) {ex.printStackTrace();} finally {try{fis.close();}catch(Exception e){e.printStackTrace();}} } } } Gianpaolo Cugola Gianpaolo Cugola 162 La classe FilterInputStream • Si tratta della sopraclasse di tutte le classi che forniscono funzionalità di filtro di vario tipo • Si appoggia ad un InputStream esistente (passato al momento della costruzione) • Fornisce tutti i metodi della classe InputStream 163 Gianpaolo Cugola La classe BufferedInputStream • Sfrutta un buffer interno per ottimizzare la lettura • Fornisce prestazioni decisamente superiori alla classica InputStream Gianpaolo Cugola Gianpaolo Cugola 164 La classe DataInputStream • Fornisce metodi per leggere i diversi tipi base del linguaggio Java da un InputStream esistente (passato al momento della costruzione) • Sfrutta lo standard UniCode per leggere i dati in maniera indipendente dalla piattaforma • Principali metodi aggiunti: – readBoolean, readByte, readInteger, readShort, readLong, readFloat, readDouble, readChar, readUnsignedByte, readUnsignedShort 165 Gianpaolo Cugola Gli altri input stream • ByteArrayInputStream – permette di creare un InputStream a partire da un array di byte (usato come sorgente di informazioni) • PipedInputStream – usato per leggere da una pipe • SequenceInputStream – usato per leggere da una sequenza di InputStream come se fossero uno solo • PushbackInputStream – permette di rimandare indietro uno o più byte letti • LineNumberInputStream e StringBufferInputStream – l’uso di queste classi è stato superato nella versione 1.1 di Java dall’introduzione delle classi Reader Gianpaolo Cugola Gianpaolo Cugola 166 Output sequenziale Object (from java.lang) OutputStream ObjectOutputStream PipedOutputStream ByteArrayOutputStream DataOutputStream FilterOutputStream BufferedOutputStream FileOutputStream PrintStream 167 Gianpaolo Cugola La classe OutputStream • Classe astratta che racchiude tutti i metodi per la scrittura da uno stream di byte • Metodi principali: – public void close() – public void flush() – public abstract void write(byte b) – public void write(byte b[]) – public void write(byte b[], int off, int len) Gianpaolo Cugola Gianpaolo Cugola 168 La classe FileOutputStream • Usata per la scrittura di file sequenziali di byte • Ridefinisce i metodi della classe OutputStream fornendone una implementazione per i file • Costruttori: – – – – public public public public FileOutputStream(String name) FileOutputStream(String name, boolean app) FileOutputStream(File f) FileOutputStream(FileDescriptor fd) • Principali metodi aggiunti – public final FileDescriptor getFD() 169 Gianpaolo Cugola La classe FileOutputStream: esercizio • Si scriva un programma Java che svolge le stesse funzioni del comando copy di dos Gianpaolo Cugola Gianpaolo Cugola 170 La classe FilterOutputStream • Si tratta della sopraclasse di tutte le classi che forniscono funzionalità di filtro di vario tipo • Si appoggia ad un OutputStream esistente (passato al momento della costruzione) • Fornisce tutti i metodi della classe OutputStream 171 Gianpaolo Cugola La classe BufferedOutputStream • Sfrutta un buffer interno per ottimizzare la scrittura di dati • Fornisce prestazioni decisamente superiori alla classica OutputStream Gianpaolo Cugola Gianpaolo Cugola 172 Le classi buffered: esercizio • Si riscriva l’esercizio precedente (copy) sfruttando le classi buffered per ottimizzare le prestazioni 173 Gianpaolo Cugola La classe DataOutputStream • Fornisce metodi per scrivere i diversi tipi base del linguaggio Java da un OutputStream esistente (passato al momento della costruzione) • Sfrutta lo standard UniCode per scrivere i dati in maniera indipendente dalla piattaforma • Principali metodi aggiunti: – writeBoolean, writeByte, writeInteger, writeShort, writeLong, writeFloat, writeDouble, writeChar, writeUnsignedByte, writeUnsignedShort Gianpaolo Cugola Gianpaolo Cugola 174 Gli altri output stream • ByteArrayOutputStream – permette di creare un OutputStream a partire da un array di byte (usato come sorgente di informazioni) • PipedOutputStream – usato per scrivere su una pipe • PrintStream – l’uso di questa classe è stato superato nella versione 1.1 di Java dall’introduzione delle classi Writer 175 Gianpaolo Cugola Lettura e scrittura sequenziale di testo • Le classi Reader e Writer inglobano le funzionalità per leggere stream sequenziali di caratteri Gianpaolo Cugola Gianpaolo Cugola 176 Reader Object (from java.lang) Reader PipedReader CharArrayReader StringReader FilterReader InputStreamReader PushbackReader FileReader BufferedReader LineNumberReader 177 Gianpaolo Cugola La classe Reader • Classe astratta che racchiude tutti i metodi per la lettura da uno stream di caratteri • Metodi principali: – public void close() – public long skip(long n) – public abstract int read() • bloccante; ritorna -1 se si è raggiunta la fine dello stream – public int read(char c[]) • bloccante; ritorna -1 se si è raggiunta la fine dello stream – public int read(char c[], int off, int len) • bloccante; ritorna -1 se si è raggiunta la fine dello stream Gianpaolo Cugola Gianpaolo Cugola 178 La classe InputStreamReader • Costituisce il ponte tra gli stream di byte e quelli di caratteri • Effettua la conversione da byte a caratteri in maniera dipendente dal particolare “encoding” adottato • Costruttori: – public InputStreamReader(InputStream is) – public InputStreamReader(InputStream is, String encoding) 179 Gianpaolo Cugola La classe FileReader • Usata per l’accesso sequenziale a file di caratteri • Ridefinisce i metodi della classe InputStreamReader fornendone una implementazione specifica per i file di caratteri • Costruttori: – public FileReader(String name) – public FileReader(File f) – public FileReader(FileDescriptor fd) Gianpaolo Cugola Gianpaolo Cugola 180 La classe FileReader: un esempio import java.io.*; public class ProvaFile { public static void main(String[] args) { if(args.length!=1) {System.err.println("Usage: ProvaFile <nome file>");System.exit(-1);} File f=new File(args[0]); FileReader fr=null; char[] c; int charRead; if(!f.exists()) System.err.println("Error: file "+args[0]+ " does not exists"); else if(!f.canRead()) System.err.println("Error: cannot read from file "+args[0]); else { c=new char[(int)f.length()]; try{ fr=new FileReader(f); charRead=fr.read(c); System.out.println(new String(c)); } catch(Exception ex) {ex.printStackTrace();} finally {try{fr.close();}catch(Exception e){e.printStackTrace();}} } } } 181 Gianpaolo Cugola La classe FilterReader • Si tratta della sopraclasse di tutte le classi che forniscono funzionalità di filtro su stream di caratteri • Si appoggia ad un Reader esistente (passato al momento della costruzione) • Fornisce tutti i metodi della classe Reader Gianpaolo Cugola Gianpaolo Cugola 182 La classe BufferedReader • Sfrutta un buffer interno per ottimizzare la lettura • Si appoggia ad un Reader esistente (passato al momento della costruzione) • Fornisce prestazioni decisamente superiori alla classica Reader • Metodi aggiunti – public String readLine() 183 Gianpaolo Cugola Gli altri Reader • CharArrayReader – un reader a partire da un array di caratteri • StringReader – un reader a partire da una stringa • PushbackReader – permette di rimandare indietro uno o più caratteri letti • LineNumberReader – public void setLineNumber(int ln) Gianpaolo Cugola Gianpaolo Cugola 184 Writer Object (from java.lang) Writer PipedWriter CharArrayWriter StringWriter BufferedWriter FilterWriter OutputStreamWriter PrintWriter FileWriter 185 Gianpaolo Cugola La classe Writer • Classe astratta che racchiude tutti i metodi per la scrittura da uno stream di caratteri • Metodi principali: – public void close() – public void flush() – public abstract void write(int) – public void write(char c[]) – public int write(char c[], int off, int len) – public void write(String s) – public int write(String s, int off, int len) Gianpaolo Cugola Gianpaolo Cugola 186 La classe OutputStreamWriter • Costituisce il ponte tra gli stream di byte e quelli di caratteri • Effettua la conversione da byte a caratteri in maniera dipendente dal particolare “encoding” adottato • Costruttori: – public OutputStreamWriter (OutputStream is) – public OutputStreamWriter (OutputStream is, String encoding) 187 Gianpaolo Cugola La classe FileWriter • Usata per la scrittura sequenziale di file di caratteri • Ridefinisce i metodi della classe OutputStreamWriter fornendone una implementazione specifica per i file di caratteri • Costruttori: – public FileWriter(String name) – public FileWriter(File f) – public FileWriter(FileDescriptor fd) Gianpaolo Cugola Gianpaolo Cugola 188 La classe FilterWriter • Si tratta della sopraclasse di tutte le classi che forniscono funzionalità di filtro su stream di caratteri • Si appoggia ad un Writer esistente (passato al momento della costruzione) • Fornisce tutti i metodi della classe Writer 189 Gianpaolo Cugola La classe BufferedWriter • Sfrutta un buffer interno per ottimizzare la scrittura • Si appoggia ad un Writer esistente (passato al momento della costruzione) • Fornisce prestazioni decisamente superiori alla classica Writer • Metodi aggiunti – public void newLine() Gianpaolo Cugola Gianpaolo Cugola 190 Reader e writer: esercizio • Si scriva un programma che copia un file di testo sostituendo i termini incontrati come specificato su linea di comando • Si scriva un programma che legge un file di testo e stampa a video solo le linee contenenti una certa stringa passata come parametro (grep) 191 Gianpaolo Cugola Gli altri Writer • CharArrayWriter – un writer a partire da un array di caratteri • StringWriter – un writer a partire da una stringa • PrintWriter – permette la stampa di tutti i tipi base di Java come stringhe – fornisce metodi analoghi a quelli dell’oggetto System.out Gianpaolo Cugola Gianpaolo Cugola 192 I file ad accesso diretto (random) • Gestiti attraverso i servizi della classe RandomAccessFile – fornisce metodi per leggere e scrivere dati – funzionalità per l’accesso diretto: • public long getFilePointer() • public native void seek(long pos) 193 Gianpaolo Cugola Altre classi del package java.io • La classe StreamTokenizer fornisce funzionalità avanzate per estrarre token da uno stream di caratteri • E’ possibile decidere liberamente i separatori da adottare Gianpaolo Cugola Gianpaolo Cugola 194 Object serialization • Meccanismo che permette la lettura e scrittura di qualsiasi oggetto Java su uno stream • Realizza una deep copy – a partire da un oggetto vengono copiati sullo stream tutti gli oggetti ad esso collegati (direttamente o indirettamente) • Gli oggetti devono implementare l’interfaccia Serializable • Vengono letti e scritti tutti gli attributi non static e non transient • Sfrutta le classi ObjectInputStream e ObjectOutputStream • Permette una semplice implementazione di oggetti persistenti 195 Gianpaolo Cugola La programmazione di rete • Consente la comunicazione tra applicazioni Java che risiedono su macchine diverse • Si possono sfruttare i socket (TCP o UDP) o la più avanzata libreria RMI Gianpaolo Cugola Gianpaolo Cugola 196 Socket TCP • Le classi per la gestione dei socket (TCP o UDP) sono parte del package java.net • Schema logico di funzionamento di una applicazione client/ server basata su socket TCP – Una applicazione “server” rimane in attesa su una porta logica – Una applicazione “client” apre una connessione verso la macchina sulla quale gira il server specificando la porta – Il server riceve la connessione e apre una canale di comunicazione – In genere i server sono applicazioni multithreaded • un thread per ogni connessione aperta più un server in attesa di nuove connessioni 197 Gianpaolo Cugola La classe ServerSocket • Usata per realizzare server che attendono connessioni TCP • Costruttore principale: – public ServerSocket(int port) • Metodi principali: – public synchronized void setSoTimeout(int timeout) • permette di scegliere un timeout per la accept (in millisecondi) – public synchronized int getSoTimeout() – public Socket accept() • bloccante se timeout=0 – public InetAddress getInetAddress() – public int getLocalPort() – public void close() Gianpaolo Cugola Gianpaolo Cugola 198 La classe Socket • Costruttori principali: – public Socket(String host, int port) – public Socket(InetAddress host, int port) • Metodi principali: – – – – – – – public public public public public public public InetAddress getInetA ddress() InetAddress getLocal Address() int getPort() int getLocalPort() InputStream getInput Stream() OutputStream getOutp utStream() void close() – public synchronized void se tSoTimeout(int timeout) • permette di scegliere un timeout per la lettura dei byte dall’InputStream associato (in millisecondi) – public synchronized int get SoTimeout() 199 Gianpaolo Cugola I socket TCP: un esempio import java.net.*; import java.io.*; public class ProvaServerTCP { public static void main(String[] args) { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(4444); } catch (IOException e) { System.out.println("Could not listen on port: " +4444+", "+e);System.exit(-1); } Socket socket = null; while(true) { try { socket = serverSocket.accept(); new ServerThread(socket).start(); } catch (IOException e) { System.out.println("Accept failed: " + 4444 + ", " + e); System.exit(1); } } } } Gianpaolo Cugola Gianpaolo Cugola class ServerThread extends Thread { Socket socket; public ServerThread(Socket s) { socket=s; } public void run() { try { BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()) ); String inputLine; while ((inputLine=br.readLine())!=null){ System.out.println(inputLine); if (inputLine.equals("Bye.")) break; } br.close(); socket.close(); } catch (IOException ex) {e.printStackTrace();} } } 200 I socket TCP: esercizio • Scrivere un programma Java che si colleghi al server precedentemente descritto ed invii una serie di stringhe prima di terminare con la stringa “Bye.” 201 Gianpaolo Cugola I socket UDP • Il protocollo UDP costituisce una alternativa al protocollo TCP • E’ caratterizzato dall’essere un protocollo unreliable e connectionless • Fornisce però prestazioni superiori • Connessioni UDP si realizzano in Java sfruttando i servizi delle classi – DatagramPacket e DatagramSocket Gianpaolo Cugola Gianpaolo Cugola 202 Le altre classi del package java.net • Il package java.net fornisce altre classi per: – usare gli URL – sfruttare il protocollo HTTP – sfruttare i servizi forniti dal multicast IP 203 Gianpaolo Cugola Remote Method Invocation • Attraverso i servizi RMI è possibile invocare metodi su un oggetto remoto • Un oggetto remoto è ogni oggetto che implementi una interfaccia che estende l’interfaccia java.rmi.Remote • Gli oggetti remoti si comportano come gli oggetti tradizionali – è possibile passare riferimenti ad oggetti remoti nelle chiamate a metodo • La differenza principale riguarda il passaggio di parametri non remoti a metodi di oggetti remoti – il passaggio è fatto per copia (i parametri devono essere serializable) • Lo stesso vale per i valori di ritorno restituiti da metodi di oggetti remoti Gianpaolo Cugola Gianpaolo Cugola 204 Implementazione di una applicazione client/server basata su RMI: server • Si crea una interfaccia che descriva i servizi forniti dal server (che estenda java.rmi.Remote) – tutti i metodi devono dichiarare di sollevare l’eccezione java.rmi.RemoteException • Si implementa il server – come sottoclasse di java.rmi.server.UnicastRemoteObject – come classe “generica” che reimplementi i metodi equals, hashCode e toString in maniera da mantenere la semantica corretta • in tal caso il server deve essere esplicitamente esportato per essere visibile ai client (metodo java.rmi.server.UnicastRemoteObject.exportObject) – il server può essere registrato sul rmiregistry attraverso un nome simbolico – il server dovrebbe impostare come security manager un RMISecurityManager • Si compila il server • Si creano le classi stub e skeleton attraverso il compilatore rmic • Si lancia il server 205 Gianpaolo Cugola Implementazione di una applicazione client/server basata su RMI: client • Si implementa il client • Il client ottiene un riferimento all’oggetto remoto – passato da altri oggetti – ottenuto accedendo all’rmiregistry • Il client può invocare tutti i metodi elencati nell’interfaccia remota implementata dal server • Non occorre un particolare processo di compilazione per il client Gianpaolo Cugola Gianpaolo Cugola 206 Implementazione di una applicazione client/server basata su RMI: rmiregistry • Il rmiregistry fornisce un servizio di directory per RMI • Un server RMI si può registrare su un rmiregistry attraverso un nome simbolico • Un client RMI può: – ottenere un riferimento ad un server RMI indicando il nome simbolico – chiedere la lista dei server disponibili • Tali servizi sono realizzati attraverso le classi: – java.rmi.Naming – java.rmi.registry.LocateRegistry – java.rmi.registry.Registry e l’eseguibile rmiregistry 207 Gianpaolo Cugola Esempio RMI: l’interfaccia del server import java.rmi.*; public interface ProvaRMIServer extends Remote { public void print(String s) throws RemoteException; } Gianpaolo Cugola Gianpaolo Cugola 208 Esempio RMI: l’implementazione del server import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class ProvaRMIServer Impl extends UnicastRemoteObject implements ProvaRMIServer { public static void main(String[] args) { try { System.setSecurityManager(new RMISecurityManager()); ProvaRMIServerImpl server = new ProvaRMIServerImpl(); Naming.rebind("polimi/ProvaRMIServer", server); System.out.println("Server bound"); } catch (Exception e) { e.printStackTrace(); } } public ProvaRMIServerImpl () throws RemoteExce ption {} public void print(String s) throws RemoteExce ption { System.out.println(s); } } 209 Gianpaolo Cugola Esempio RMI: il client import java.rmi.*; public class ProvaRMIClient { public static void main(String[] args) { try { System.out.println("Looking up server..."); ProvaRMIServer server = (ProvaRMIServer) Naming.lookup("rmi:// "+ args[0]+ "ProvaRMIServer"); System.out.println("Server bound..."); server.print("prima prova"); server.print("seconda prova"); } catch (Exception e) { e.printStackTrace(); } } } Gianpaolo Cugola Gianpaolo Cugola 210 Esempio RMI: la compilazione • javac ProvaRMIServerImpl – compila il server • java ProvaRMIClient – compila il client • rmic ProvaRMIServerImpl – crea le classi ProvaRMIServer_Skel e ProvaRMIServer_Stub • rmiregistry – lancia il registry • java ProvaRMIServerImpl – lancia il server • java ProvaRMIClient localhost – lancia il client dicendo di collegarsi a localhost 211 Gianpaolo Cugola Il deployment • Le classi stub devono essere accessibili al client (attraverso un opportuno class loader) • Il caso delle applet – le classi stub devono essere inserite nella stessa directory della classe dell’applet (sul server http) • il classloader usato è AppletClassLoader – il server RMI deve girare sullo stesso host su cui gira il server http dal quale viene scaricata l’applet Gianpaolo Cugola Gianpaolo Cugola 212