package chat;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* Classe per costruire un archivio di entità <code>Contatto</code>
* ordinate in modo crescente sulla base del campo <code>nome</code>.
* Realizza un semplice <i>database</i> che usa il nome come campo
* chiave di ricerca.
* <p>
* Idonea anche a situazioni <i>multi-thread</i>.
* <p>
*
* @author <em>Marco Cimatti</em>
* @version 1.0
* @see Contatto
* @see Contatto#nome()
*/
public class Database {
/** La tabella ad albero binario ordinata che contiene i singoli <i>record</i>. */
private SortedSet s = Collections.synchronizedSortedSet(new TreeSet(new ComparaContatto()));
/** Costruttore che istanzia un <i>database</i> vuoto. */
public Database() {}
/**
* Costruttore che legge il contenuto del <i>database</i> da un
* file. Adotta <code>Parser</code> per processare il file ASCII
* il cui nome è passato come parametro.
*
* @param nome_file il nome del file ASCII da leggere.
* @exception FileNotFoundException se il file indicato manca.
* @exception IOException in caso di errori accedendo in lettura al file.
* @see Parser
*/
public Database(String nome_file) throws FileNotFoundException, IOException {
InputStreamReader is = new InputStreamReader(new FileInputStream(nome_file));
try {
Parser p = new Parser(is);
p.avanzaToken();
while (p.tokenCorrente().length() > 0)
modifica(p.prossimo());
} finally { is.close(); }
}
/**
* <b>Modificatore primitiva</b> per aggiungere un <i>record</i>
* all'archivio; se è già presente una <i>entry</i> avente lo
* stesso nome di <code>c</code> allora essa viene sovrascritta.
* Questo evita di avere più elementi con lo stesso nome.
*
* @param c il <code>Contatto</code> da modificare/aggiungere.
* @see Contatto#nome()
*/
public synchronized void modifica(Contatto c) {
s.remove(c);
s.add(c);
}
/**
* <b>Predicato primitiva</b> per verificare l'appartenenza di
* un certo nominativo entro l'archivio.
*
* @param chi il nome del <code>Contatto</code> da cercare.
* @return <code>true</code> se e solo se è presente un
* <i>record</i> avente <code>nome() == chi</code>;
* <code>false</code> altrimenti.
*/
public synchronized boolean contiene(String chi) {
return s.contains(new Contatto(chi, null, null));
}
/**
* <b>Selettore primitiva</b> per ottenere un certo elemento
* dall'archivio.
*
* @param chi il nome del <code>Contatto</code> da selezionare.
* @return <code>null</code> se e solo se non è presente un
* <i>record</i> avente <code>nome() == chi</code>;
* il <code>Contatto</code> richiesto altrimenti.
*/
public synchronized Contatto seleziona(String chi) {
return contiene(chi) ? (Contatto) s.tailSet(new Contatto(chi, null, null)).first()
: null;
}
/**
* <b>Modificatore primitiva</b> per eliminare un elemento.
*
* @param chi il nome del <code>Contatto</code> da cancellare.
*/
public synchronized void cancella(String chi) {
s.remove(new Contatto(chi, null, null));
}
/**
* <b>Modificatore</b> per azzerare l'archivio; <b>primitiva</b>
* solo per questione di comodità ed efficienza.
*/
public synchronized void cancella() {
s.clear();
}
/**
* <b>Accesso</b> per ottenere il numero di elementi contenuti;
* <b>primitiva</b> solo per questioni di comodità ed efficienza.
*
* @return il numero di <i>record</i> presenti nell'archivio.
*/
public synchronized int quanti() {
return s.size();
}
/**
* <b>Accesso primitiva</b> per ottenere tutti gli elementi.
*
* @return tutti i <i>record</i> presenti nell'archivio;
* l'<i>array</i> restituito può avere lunghezza nulla
* qualora il <i>database</i> sia vuoto.
*/
public synchronized Contatto[] tutti() {
return (Contatto[]) s.toArray(new Contatto[s.size()]);
}
/**
* <b>Convertitore</b> per ottenere la rappresentazione testuale
* del contenuto dell'archivio, conforme alla grammatica definita
* da <code>Parser</code> per esprimere un <code>Contatto</code>.
* non è una <b>primitiva</b>.
*
* @return una stringa rappresentante l'intero <i>database</i>.
* @see Parser
* @see Contatto
*/
public synchronized String toString() {
String ret = "";
Contatto[] v = tutti();
for (int i = 0; i < v.length; ++i)
ret += v[i] + "\n";
return ret;
}
}
/**
* Classe di utilità per ordinare gli elementi all'interno di un
* <code>Database</code>; contiene solo un metodo che effettua
* il confronto fra due oggetti di tipo <code>Contatto</code>,
* ordinandoli in senso crescente sulla base del <code>nome()</code>.
* <p>
*
* @author <em>Marco Cimatti</em>
* @version 1.0
* @see Database
* @see Contatto
* @see Contatto#nome()
*/
class ComparaContatto implements Comparator {
/**
* Realizza il confronto fra due <code>Contatto</code>.
*
* @return un valore negativo, nullo o positivo a sconda che il
* <code>Contatto o1</code> sia minore, uguale o maggiore
* del <code>Contatto o2</code>, valutandolo sulla base
* dell'attributo <code>nome()</code>.
* @see Contatto
* @see Contatto#nome()
*/
public int compare(Object o1, Object o2) {
return ((Contatto) o1).nome().compareTo(((Contatto) o2).nome());
}
}
syntax highlighted by Code2HTML, v. 0.8.11