Vediamo in questa lezione un esempio di sviluppo programmatico delle transazioni. Come esempio ci rifaremo proprio all'ambito bancario, grazie anche alla presenza del componente BankAccount, sviluppato nelle scorse lezioni.
Vedremo proprio come grazie allo sviluppo per componenti sia possibile creare livelli di servizio sempre più avanzati, riutilizzando gli strumenti base già a disposizione. Quello che faremo sarà estendere la web application che si occupava di amministrare i conti correnti bancari, aggiungendo una nuova funzione, il bonifico.
Il bonifico è un'operazione di scambio denaro tra due conti correnti: si identificano i due conti, si fa un prelievo dal conto mittente e si fa un deposito sul conto destinatario. Avremmo due possibilità per fare questa operazione. La prima è quella di creare uno stateless session bean in cui eseguire la logica: in questo modo potremmo sfruttare il modello dichiarativo delle transazioni. La seconda è quella di prevedere una funzione sul controller ed utilizzare il modello programmatico delle transazioni ed è quello che andremo a fare.
Riprendiamo la servlet che funge da controllo. Aggiungiamo il metodo che si occupa dell'operazione di bonifico.
//Controller.java
..//
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
..//
//Nuovo metodo di logica
if (op.equalsIgnoreCase("bonifico"))
doBonifico(request,response);
}
//Il metodo effettua l'operazione di bonifico, preoccupandosi di gestire la logica transazionale dell'operazione in maniera programmatica
private void doBonifico(HttpServletRequest request, HttpServletResponse response) throws IOException {
//Recupero i parametri necessari a portare a termine l'operazione
String idBeneficiario=request.getParameter("idBeneficiario");
String idMittente=request.getParameter("idMittente");
String amount=request.getParameter("amount");
double amt=Double.parseDouble(amount);
//Recupero la transazione dall'ambiente di esecuzione
UserTransaction ut=null;
try {
ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
} catch (NamingException e2) {
e2.printStackTrace();
return;
}
try {
//Inizio la transazione
ut.begin();
//effettuo l'operazione di prelievo dal mittente
BankAccountLocal mit = bah.findByPrimaryKey(new AccountPK(idMittente));
mit.prelievo(amt);
//effettuo l'operazione di deposito sul beneficiario
BankAccountLocal ben = bah.findByPrimaryKey(new AccountPK(idBeneficiario));
ben.deposito(amt);
//tutte le operazioni sono andate a buon fine, commit!
ut.commit();
response.getOutputStream().println("L'operazione di bonifico è andata a buon fine.");
} catch (Exception e) {
try {
System.out.print("Rolling back...");
ut.rollback();
System.out.println("... done");
} catch (Exception e1) {
e1.printStackTrace();
}
e.printStackTrace();
//Segnalazione di operazione riuscita
response.getOutputStream().println("Operazione non riuscita!"+e.getMessage());
}
}
..//
Dopo aver recuperato i parametri, recuperiamo un oggetto UserTransaction
dall'ambiente di esecuzione. Per i dettagli di questo oggetto si può leggere la documentazione delle JTA. La transazione deve mantenere tra il metodo begin()
e commit()
le operazioni che la definiscono ed eseguire il rollback()
nel caso in cui ci siano delle eccezioni.
Come si vede dal codice in rosso, la logica è molto semplice ed intuitiva. Se va tutto bene, effettuiamo il commit()
, cioè rendiamo effettive le operazioni svolte sinora, altrimenti effettuiamo il rollback()
, cioè ripristiniamo lo stato di partenza (indicato dal begin()
).
Il recupero delle transazioni dall'ambiente di esecuzione avviene, al solito, tramite una chiamata JNDI. L'application server si occuperà di instanziarne una e restituirla al chiamante.
Modificate la pagina index.html, aggiungendo la form per chiamare questa operazione:
..//
<h3>Operazione di bonifico</h3>
<form action="controller">
<input type="hidden" name="op" value="bonifico" /;>
ID Mittente: <input type="text" name="idMittente" /><br/><br/>
ID Beneficiario: <input type="text" name="idBeneficiario" /><br/><br/>
Ammontare: <input type="text" name="amount" /><br/><br/>
<input type="submit" value="Invia" />
</form>
..//
Per far fallire l'applicazione e testare l'efficacia della transazione sarà sufficiente inserire un beneficiario errato.
Ecco la risposta del server sia in caso positivo, sia in caso negativo.