mercoledì 11 giugno 2008

Schermare le RemoteException

Consideriamo un'applicazione architettura client server basata su RMI.
Il client deve accedere dialoga con il server usando l'interfaccia remota di quest'ultimo. Per fissare le idee supponiamo che il server abbia la seguente interfaccia:

public interface League extends Remote {
void addTeam(String name) throws RemoteException;
void removeTeam(String name) throws RemoteException;
List getTeamList() throws RemoteException;
int getTeamsCount() throws RemoteException;
}



Come richiesto da RMI, per ogni metodo è specificato che può sollevare una RemoteException. Le RemoteException dovrebbero essere gestita dal client, ovvero le chiamate dei metodi dovrebbero essere racchiuse in un blocco try/catch come il seguente:

TeamManager manager = ...; try { n = manager.getTeamsCount(); } catch(RemoteException ex) { // gestione dell'eccezione }

Se le chiamate al server sono sparse in varie parti del codice del client la gestione delle eccezioni potrebbe diventare tediosa e ripetitiva.
Utilizzando la tecnica descritta di seguito è possibile concentrare la gestione delle RemoteException in un unico punto.
L'idea è quella di interfacciare il codice client con interfaccia simile a quella remota che però non richieda la gestione delle RemoteException, nel nostro caso:

public interface LocalLeague { void addTeam(String name); void removeTeam(String name); List getTeamList(); int getTeamsCount(); }

La soluzione si basa sul concetto di adapter.
Creiamo un oggetto 'adapter' che implementa l'interfaccia locale e delega le chiamate al server remoto. La gestione delle RemoteException e gestita dall'adapter che di fatto le intercetta prima che possano arrivare al client.
La situazione che si vuole ottenere e schematizzata in figura.


Il client utilizza l'interfaccia semplificata (senza RemoteException).
L'adapter inoltra le chiamate al server, e nel caso gestisce la RemoteException catturandola prima che arrivi al client. Dato che il client richiede comunque una risposta nel caso di un'eccezione l'adapter interroga un oggetto fallback che fornisce il valore da restiuire in questi casi.
Nel nostro caso l'oggetto di fallback è il seguetne:


LocalLeague fallback = new LocalLeague() { public void addTeam(String name) { // nothing } public void removeTeam(String name) { // nothing } public List getTeamList() { return Collections.emptyList(); } public int getTeamsCount() { return 0; } };


In oltre l'adapter è in grado di segnalare le eccezioni interfacciandosi con un oggetto ExceptionListener. L'interfaccia ExceptionListener è definita nel package java.beans nel seguente modo:


public interface ExceptionListener { void exceptionThrown(Exception e); }

Fornedo la propria implementazione di ExceptionListener il client può gestire tutte le RemoteException in un unico punto.
La creazione dell'oggetto adapter avviene nel seguente modo:

LocalLeague adapter = AdapterFactory.adapt(LocalLeague.class, remoteServer, fallback, exceptionListener);