Dopo avere introdotto nell'articolo precedente i Session Bean Stateless ne vediamo ora un utilizzo pratico. Abbiamo precedentemente realizzato un carrello e-commerce utilizzando i Session Bean Stateful 3.0; in questo articolo vedremo come possono essere impiegati i Session Bean Stateless 3.0 per realizzare la funzione di “visualizzazione dettaglio” dei prodotti da inserire nel carrello.
L'utilizzo dei Session Bean Stateless nella realizzazione di questa funzione è giustificato dal fatto che il “dettaglio di un prodotto” inteso come visualizzazione di quelli che sono i suoi attributi (prezzo, descrizione, quantità disponibili etc) è invariante nel tempo, per cui il risultato di tale visualizzazione non dipende né dal momento in cui tale dettaglio viene richiesto (la descrizione o il prezzo di un prodotto sono sempre gli stessi) né da chi lo richiede (poco importa se il dettaglio viene richiesto da un utente A o da un utente B).
Per di più essendo un'operazione di consultazione, tale attività non richiede la memorizzazione in sessione di alcun dato per cui può completarsi attraverso un semplice pattern “richiesta-risposta” per il quale vengono appunto impiegati i Session Bean Stateless.
Dal momento che provvederemo ad apportare delle modifiche al progetto preesistente, è il caso di ricordare che questo era composto dai seguenti moduli:
web-carrello
: contenente servlet e jsp di visualizzazioneejb-carrello
: contenente l'EJB Stateful che conserva lo stato del carrello, e il nuovo EJB Stateless che estrae le informazioni di visualizzazioneejb-carrelloClient
: contenente la definizione dell'interfaccia dell'EJB Stateful e Statelessutils-carrello
: contenente le classi di ausilio
A tali progetti farà riferimento il progetto principale:
carrello
: contenente il file application.xml di configurazione dei vari moduli.
Modifiche al progetto utils-carrello
Il progetto utils-carrello che precedentemente conteneva esclusivamente la definizione della classe Oggetto.java
che rappresenta gli oggetti che verranno inseriti all'interno nel carrello, viene arricchito di due nuove classi: Info.java
e VirtualDb.java
.
La prima classe raccoglie tutte le informazioni relative al dettaglio di un oggetto ovvero:
- id: identificativo numerico dell'oggetto
- nome: il nome del prodotto
- disponibilità: la quantità di oggetti presenti nell'e-commerce
- descrizione: la descrizione delle caratteristiche del prodotto
- prezzo dell'oggetto
- la percentuale di sconto applicata
package web.util;
public class Info {
private int id;
private String nome;
private int disponibilita;
private String descrizione;
private float prezzo;
private float sconto;
// getters/setters...
}
insieme ai metodi get e set corrispondenti a tali proprietà.
La seconda VirtualDb.java
è una classe di ausilio che rappresenta un database virtuale che restituisce a seconda dell'id ricevuto come argomento il dettaglio (quindi l'oggetto Info) corrispondente all'oggetto avente quell'id.
package web.util;
public class VirtualDb {
public static Info get(int indice) {
Info informazione = new Info();
if (indice==0) {
informazione.setId(0);
informazione.setNome("Oggetto 0");
informazione.setDescrizione("Descrizione 0");
informazione.setPrezzo(10);
informazione.setDisponibilita(5);
informazione.setSconto(10);
} else if (indice==1) {
informazione.setId(1);
informazione.setNome("Oggetto 1");
informazione.setDescrizione("Descrizione 1");
informazione.setPrezzo(20);
informazione.setDisponibilita(15);
informazione.setSconto(5);
} else if (indice==2) {
informazione.setId(2);
informazione.setNome("Oggetto 2");
informazione.setDescrizione("Descrizione 2");
informazione.setPrezzo(30);
informazione.setDisponibilita(15);
informazione.setSconto(5);
}
return informazione;
}
}
Come vediamo l'implementazione del metodo prevede la presenza di tre id diversi (0, 1, 2) e restituisce a seconda dell'id ricevuto un oggetto Info differente.
Ovviamente nel caso di implementazioni concrete tale classe viene sostituita da appositi Entity Bean (vedremo di che si tratta negli articoli che seguiranno) che recuperano le informazioni direttamente dal DB.
Modifiche ai progetti ejb-carrelloClient ed ejb-carrello
I progetti ejb-carrelloClient
ed ejb-carrello
che in precedenza contenevano la definizione rispettivamente dell'interfaccia dell'EJB Statefull e la sua relativa implementazione, vengono arricchiti di due nuovi file.
Il primo DettaglioLocal.java
(contenuto in ejb-carrelloClient
) contiene la definizione dell'interfaccia che verrà implementata dall'EJB Stateless.
Tale interfaccia prevede la presenza di un solo metodo getDettaglio
che riceve come argomento un id intero e restituisce un oggetto Info
(di cui abbiamo discusso in precedenza):
package web.ejb;
import javax.ejb.Local;
import web.util.Info;
@Local
public interface DettaglioLocal {
public Info getDettaglio(int indice);
}
Notiamo che l'interfaccia è annotata con @Local perché utilizzata all'interno del contesto dell'Application Server.
Il secondo file Dettaglio.java (contenuto in ejb-carrello) contiene l'implementazione di tale interfaccia e quindi del metodo getDettaglio in essa contenuto:
package web.ejb;
import javax.ejb.Stateless;
import web.util.Info;
import web.util.VirtualDb;
@Stateless
public class Dettaglio implements DettaglioLocal {
public Dettaglio() { ... }
public Info getDettaglio(int indice) {
return VirtualDb.get(indice);
}
}
Come vediamo la classe Dettaglio viene annotata con @Stateless (l'EJB infatti, per le ragioni di cui abbiamo parlato all'inizio di questo articolo, sarà un Session Bean di tipo Stateless) e l'implementazione del metodo getDettaglio non fa altro che invocare il metodo static get della classe VirtualDb.
Successivamente, quando introdurremo gli Entity Bean, vedremo come recuperare direttamente le informazioni dal Db e come modificare di conseguenza tale classe per accedere a tali informazioni.
Modifiche al progetto web-carrello
Gli aggiornamenti al progetto web-carrello
riguardano essenzialmente la modifica del metodo doPost
della classe CarrelloServlet
preesistente, l'inserimento del pulsante di dettaglio per ogni oggetto del carrello nella pagina index.jsp
e la creazione di una nuova pagina dettaglio.jsp
riepilogativa delle informazioni del prodotto selezionato.
Per quanto riguarda le modifiche alla classe CarrelloServlet queste riguardano essenzialmente l'injection dell'EJB Stateless DettaglioLocal
e la modifica del metodo doPost per gestire il caso in cui viene richiesto il “dettaglio” di un oggetto del carrello.
public class CarrelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
CarrelloLocal carrello;
@EJB
DettaglioLocal dettaglio;
public CarrelloServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getParameter("azione").equals("dettaglio")){
request.getSession().setAttribute("dettaglio", dettaglio.getDettaglio(Integer.parseInt(request.getParameter("id"))));
response.sendRedirect("/web-carrello/dettaglio.jsp");
} else {
if (request.getParameter("azione").equals("aggiungi")) {
Oggetto oggetto = new Oggetto();
oggetto.setId(Integer.parseInt(request.getParameter("id")));
oggetto.setNome(request.getParameter("nome"));
carrello.aggiungi(oggetto);
} else if (request.getParameter("azione").equals("rimuovi")) {
carrello.rimuovi(Integer.parseInt(request.getParameter("indice")));
}
request.getSession().setAttribute("carrello", carrello.getOggettiCarrello());
response.sendRedirect("/web-carrello");
}
}
}
La pagina di visualizzazione dei dettagli: dettaglio.jsp
In particolare rispetto all'implementazione precedente la modifica del metodo doPost
prevede l'invocazione del metodo getDettaglio dell'EJB Stateless quando il parametro azione della richiesta è “dettaglio” (passando a tale metodo l'id dell'oggetto di cui si vuole visualizzare il dettaglio), l'inserimento dell'oggetto Info da questo restituito nella variabile di sessione “dettaglio” e il redirect verso la pagina dettaglio.jsp
.
La pagina dettaglio.jsp è così costituita:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ page import="java.util.ArrayList, web.util.Info;" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Carrello</title>
</head>
<body>
<div>
<div style="font-family:Verdana; text-align:center; background-color: #ddd; border: 1px #ddd solid; width: 330px">
Dettaglio Prodotto
</div>
<div style="border: 1px #ddd solid; width:330px">
<%
Info informazioni = (Info)(session.getAttribute("dettaglio"));
if (informazioni!=null)
{
%>
<div style="margin:5px; position:relative; height:20px;">
<div style="text-align:center; position: absolute; top:0px; left:0px; width:155px; height:20px; background-color: #eee">
<strong>Id</strong>
</div>
<div style="text-align:center; position: absolute; top:0px; left:165px; width:155px; height:20px; background-color: #eee">
<% out.print(informazioni.getId()); %>
</div>
</div>
<div style="margin:5px; position:relative; height:20px;">
<div style="text-align:center; position: absolute; top:0px; left:0px; width:155px; height:20px; background-color: #eee">
<strong>Nome</strong>
</div>
<div style="text-align:center; position: absolute; top:0px; left:165px; width:155px; height:20px; background-color: #eee">
<% out.print(informazioni.getNome()); %>
</div>
</div>
<div style="margin:5px; position:relative; height:20px;">
<div style="text-align:center; position: absolute; top:0px; left:0px; width:155px; height:20px; background-color: #eee">
<strong>Descrizione</strong>
</div>
<div style="text-align:center; position: absolute; top:0px; left:165px; width:155px; height:20px; background-color: #eee">
<% out.print(informazioni.getDescrizione()); %>
</div>
</div>
...
<%
}
%>
</div>
</div>
</body>
</html>
Tale pagina, non fa altro che recuperare l'oggetto Info
dalla sessione utente e se questo è diverso da null visualizza le informazioni in essa contenute recuperando attraverso i corrispondenti metodi get i valori delle proprietà che costituiscono il dettaglio dell'oggetto.
Infine la pagina index.jsp preesistente viene modificata in maniera tale da inserire per ogni prodotto del carrello, un form con la richiesta del “dettaglio”:
<form method="post" action="./CarrelloServlet" style="position: absolute; top:10px; left: 290px;" target="_blank">
<input type="hidden" name="azione" value="dettaglio" />
<input type="hidden" name="id" value="1" />
<input type="submit" value="?" style="border: 1px #ddd solid; height:30px; width:30px; " />
</form>
Come vediamo tale form prevede la presenza di un campo hidden “azione” valorizzato con “dettaglio”, l'id dell'oggetto di cui occorre visualizzare il dettaglio ed ovviamente il pulsante di submit.
Una volta effettuato il deploy dell'applicazione questo sarà il risultato:
Come vediamo accando ad ogni prodotto che è possibile inserire nel carrello avremo un pulsante “?” che ci permetterà di visualizzare il dettaglio del prodotto corrispondente.
Una volta cliccato su tale pulsante si aprirà una nuova pagina contenente il dettaglio del prodotto, come nel seguente esempio:
Per gli approfondimenti riguardo il codice rimandiamo al progetto eclipse in allegato.