Java EE 4 Laboratorio di Ingegneria del software Andrea Bei
Java EE Pattern Web Tier Model 1 e Model 2 (MVC) Front Controller Service To Worker Business Tier Data Access Object (Integration Tier) Business Delegate Service Locator Risorse Understanding JavaServer Pages Model 2 architecture http://www.javaworld.com/javaworld/jw-12-1999/jw-12-ssj-jspmvc.html Core J2EE Pattern http://java.sun.com/blueprints/corej2eepatterns/patterns/index.html J2EE Pattern Catalog http://java.sun.com/blueprints/patterns/catalog.html
Model 1 (*) (*) I JavaBean possono interfacciarsi al DB direttamente o mediante oggetti DAO (scelta migliore) Architettura Model 1: Le pagine JSP processano le richieste, creano e usano JavaBean per elaborare le risposte La logica di business è incapsulata nei JavaBean la presentazione è implementata dalle pagine JSP La separazione presentazione/logica di business non è netta: le chiamate ai metodi dei JavaBean sono effettuate all interno delle pagine JSP Ciò comporta che le pagine JSP sono poco manutenibili dai web designer ed è difficile distinguere nettamente le responsabilità tra web designer e developer E un modello adatto solo per applicazioni semplici
Model View Controller Il Pattern Model View Controller (MVC) prevede la progettazione dell applicazione in 3 componenti 1. Model: Logica Di Business 2. View: Logica di Presentazione 3. Controller: Logica di Controllo Il controller ha la responsabilità di Trasformare le interazioni dell'utente sulla View in azioni sul modello Selezionare le View richieste ( pagine nel caso di web application)
Model 2 (*) (*) I JavaBean possono interfacciarsi al DB direttamente o mediante oggetti DAO (scelta migliore) Architettura Model 2: E una implementazione di MVC Il Controller è una Servlet che esegue le seguenti azioni per ogni request Riceve la request e in base all azione codificata nella request Crea i bean contenenti i dati visualizzati dalla pagina JSP di destinazione e li inserisce in sessione o nell oggetto request (scelta migliore) (2) Decide la JSP a cui inoltrare la richiesta ed esegue il forward della request (inoltro) (3) La View è una JSP E responsabile di recuperare i bean creati dal controller (4), estrarne il contenuto creando dinamicamente la pagina Il Model è un JavaBean
Model 1: caso di studio libreria Architettura di tipo Model 1 Presentation, Application, Services Java Bean JSP,HTML Domain Data transfer object DAO Collection di Data transfer object Persistence DB
Model 1: caso di studio libreria Realizzazione caso d uso Inserimento Autore (Architettura) Presentation, Application, Services Autore Bean insautore.html insautore.jsp Domain Autore Libreria Persistence DB
Model 1: caso di studio libreria Dati inviati tramite un form. insautore.html <html> <head> <title>inserimento Autore</title> </head> <body> <form method="post" action= insautore.jsp"> <p>nome:<input type="text" name="nome" size="20"></p> <p>cognome: <input type="text" name="cognome" size="20"></p> <p>data di Nascita: <input type="text" name= data" size="20"></p> <p>luogo di Nascita: <input type="text" name= luogo" size="20"></p> <p><input type="submit" value="invia" name="b1"> </form> </body> </html>
Model 1: caso di studio libreria <html> <head> <title>inserisciautore</title> </head> <%@ page import= AutoreBean"%> <body> <%=request.getparameter("nome")%><br> <%=request.getparameter("cognome")%><br> <%=request.getparameter( data")%><br> <%=request.getparameter( luogo")%><br> <jsp:usebean id= autore" class= AutoreBean" scope="page"> <jsp:setproperty name= autore" property="nome value="<%=request.getparameter("nome")%>"/> <jsp:setproperty name= autore " property="cognome" value="<%=request.getparameter("cognome")%>"/> <jsp:setproperty name= autore " property= datadinascita" value="<%=request.getparameter(" datadinascita ")%>"/> <jsp:setproperty name= autore " property= luogodinascita" value="<%=request.getparameter(" luogodinascita ")%>"/> <% autore.inserisci(); %> </jsp:usebean> </body></html> insautore.jsp
Model 1: caso di studio libreria public class AutoreBean { private String nome; private String cognome; private String datadinascita; private String luogodinascita; AutoreBean.java public void setnome(string nome){ this.nome=nome; public String getnome(){ return nome; // altri metodi getter e setter per cognome, datadinascita, luogodinascita public void inserisci(){ Libreria libreria=new Libreria ( libreria, libreria, libreria ); Autore autoredto=new Autore(nome,cognome, datadinascita, luogodinascita); libreria.inserisciautore(autoredto);
Model 2: caso di studio libreria Realizzazione caso d uso Seleziona il genere (navigazione) Ricerca.html (1) request GET action=listageneri public class ricerca extends HttpServlet { private processrequest(...,...) { Servlet ricerca Impl. processrequest SelezioneGenere.jsp public void doget(..,..) { processrequest(...,...) public void dopost(..,..) { processrequest(...,...) SelezioneLibro.jsp
Model 2: caso di studio libreria <html> Ricerca.html <head> <title>ricerca</title> </head> <body> <p align="center"><font SIZE="+3" COLOR="#800000" FACE="Tahoma"><b>Seleziona il tipo di ricerca</b></font> <table BORDER="0" align="center"> <tr><td> <a href="http://localhost/servlet/libreria/ricerca?action=listageneri">genere</a> </td></tr> <tr><td> <a href="http://localhost/servlet/libreria/ricerca?action=listaautori">autore</a> </td></tr> <tr><td> <a href="http://localhost/servlet/libreria/ricerca? action=listatitoli">titolo</a> </td></tr> </table></p> </body> </html>
Model 2: caso di studio libreria import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; import Libreria; Servlet ricerca public class ricerca extends HttpServlet { Libreria l; public void init(servletconfig config) throws ServletException { l=new Libreria("libreria","libreria","libreria"); super.init(config);
Model 2: caso di studio libreria protected void processrequest(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { String page; String action = request.getparameter("action"); if (action.equals( listageneri ) { // (1) // vengono recuerati i dati e resi disponibile alla JSP Collection listageneri = l.getlistageneri(); request.setattribute(" listageneri ", listageneri ); Servlet ricerca // si decide la JSP a cui forwardare la richiesta page= SelezioneGenere.jsp ; //(2) //. Il codice relativo alle altre action sarà descritte in seguito dispatch(request, response, page); protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { processrequest(request, response); protected void dopost(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { processrequest(request, response); protected void dispatch(httpservletrequest request, HttpServletResponse response, String page) throws javax.servlet.servletexception, java.io.ioexception { RequestDispatcher dispatcher = getservletcontext().getrequestdispatcher(page); dispatcher.forward(request, response);
Model 2: caso di studio libreria <%@ page session ="true" %> <html> <title>selezione Nome</title> <body><p align="center"> <font SIZE="+3" COLOR="#800000" FACE="Tahoma"> <b>seleziona il genere</b></font></p> <% Collection c= (Collection) request.getattribute("listageneri"); %> <form method="post" action="/servlet/libreria/ricerca"> <input type="hidden" name="action" value= listalibri"> <center> <select name="genere" size="1"> <% Iterator i=c.iterator(); while (i.hasnext()) { String genere = (String) i.next(); %> <option value="<%=genere%>"><%=genere%></option> <% %> </select> <input type="submit" value="invia" name="b1"></center>" </form> </html> SelezioneGenere.jsp
Model 2: caso di studio libreria Servlet ricerca protected void processrequest(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { String page; String action = request.getparameter("action"); if (action.equals( listageneri ) { //(1) // vengono recuerati i dati e resi disponibile alla JSP Collection listageneri = l.getlistageneri(); request.setattribute(" listageneri ", listageneri ); // si decide la JSP a cui forwardare la richiesta page= SelezioneGenere.jsp ; //(2) if (action.equals( listalibri ) { //(3) // vengono recuerati i dati e resi disponibile alla JSP Collection listalibri = l.getlistalibri(); request.setattribute(" listalibri ", listalibri ); // si decide la JSP a cui forwardare la richiesta page= SelezioneLibro.jsp ; //(4) //. codice relativo ad altre Action dispatch(request, response, page);
Model 2: caso di studio libreria <%@ page session ="true" %> <html> <title>seleziona Libro</title> <body><p align="center"> <font SIZE="+3" COLOR="#800000" FACE="Tahoma"> <b>seleziona il Libro</b></font></p> <% Collection c= (Collection) request.getattribute("listalibri"); %> <form method="post" action="/servlet/libreria/ricerca"> <input type="hidden" name="action" value= schedalibro"> <center> <select name= libro" size="1"> <% Iterator i=c.iterator(); while (i.hasnext()) { String libro = (String) i.next(); %> <option value="<%=libro%>"><%=libro%></option> <% %> </select> <input type="submit" value="invia" name="b1"></center>" </form> </html> SelezioneLibro.jsp
Front Controller Contesto La gestione delle richieste dello strato di presentazione può essere centralizzata (una sola servlet) o decentralizzata (più servlet) Problema l sistema può avere un punto di accesso centralizzato per supportare: Servizi tecnici (autenticazione, autorizzazione, logging, tracciamento della navigazione dell utente, ) Il recupero dei dati La gestione delle viste e della navigazione Se non si ha un accesso centralizzato: Ogni View fornisce i propri servizi tecnici (codice duplicato) La logica di navigazione è lasciata alle View. Non si supporta High Coesion perché le View dovrebbero essere responsabili solo della presentazione Forze Sono necessari dei servizi tecnici centralizzati Esistono molte View che possono essere create con la stessa logica di business La logica dei servizi tecnici e della navigazione è complessa
Front Controller Soluzione: si usi un controller come punto iniziale di accesso per la gestione di richieste. Il controller gestisce le richieste Invocando i servizi tecnici Delegando i processi di business Gestendo la scelta della View opportuna (logica di navigazione) Gestendo gli errori Gestendo la strategia di creazione dei contenuti (DAO, EJB,..)
Front Controller public class EmployeeController extends HttpServlet { public void init(servletconfig config) throws ServletException { super.init(config); protected void processrequest(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { String page; /*preleva le configurazioni di sistema es: pagina di errore **/ ApplicationResources resource = ApplicationResources.getInstance(); try { // Un oggetto helper preleva il valore dei parametri RequestHelper helper = new RequestHelper(request); Command cmdhelper= helper.getcommand(); page = cmdhelper.execute(request, response); // viene eseguita l azione catch (Exception e) {page = resource.geterrorpage(e); dispatch(request, response, page); // inoltra la richiesta alla View
Front Controller protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { processrequest(request, response); protected void dopost(httpservletrequest request,httpservletresponse response) throws ServletException, java.io.ioexception { processrequest(request, response); protected void dispatch(httpservletrequest request,httpservletresponse response,string page) throws javax.servlet.servletexception, java.io.ioexception { RequestDispatcher dispatcher = getservletcontext().getrequestdispatcher(page); dispatcher.forward(request, response);
Front Controller Strategia Command e Controller Basato sul Command Pattern [GoF] Suggerisce di fornire una interfaccia comune ai componenti helper (*) Supporta Protected Variation rispetto all aggiunta o modificare dei componenti helper non ha impatto sul controller E un approccio valido per tutti i tipi di client (non solo Web) Facilita la creazione di comandi composti (Composite [Gof]) Il termine Action ed il termine Command sono usati spesso come sinonimi (*) COMPONENTI HELPER Sono Pure Fabrication di supporto ( Helper ) In questo caso il supporto è fornito al controller per individuare il comando/azione da eseguire in base ai parametri della request
Front Controller Strategia Command e Controller protected void processrequest(httpservletrequest request, HttpServletResponse response) throws ServletException, java.io.ioexception { String resultpage; try { RequestHelper helper = new RequestHelper(request); /** il getcommand() internamente usa un factory per recuperare i command objects come segue: Command command = CommandFactory.create(request.getParameter("op")); **/ Command command = helper.getcommand(); // delega la richiesta ad un helper di tipo command object resultpage = command.execute(request, response); catch (Exception e){resultpage = ApplicationResources.getInstance(). geterrorpage(e); dispatch(request, response, resultpage);
Service To Worker Contesto Il sistema controlla il flusso di esecuzione ed accede ai dati di business con cui crea dinamicamente le viste Problema La combinazione dei problemi di Front Controller e View Helper Forze Si eseguono le fasi di Autenticazione e Autorizzazione per ogni richiesta Il codice delle Scriptlet nelle View deve essere minimizzato La logica di business deve essere incapsulata in componenti Il flusso di controllo è complesso La logica di gestione delle viste e della navigazione è complessa Soluzione Si creino un controller e un dispatcher combinati con View ed Helper Il controller delega a classi Helper il recupero di dati dallo strato di business Il dispatcher è responsabile per la gestione delle View e la navigazione e può essere incapsulato direttamente nel controller o in un altraclasse
Service To Worker autenticazione, autorizzazione, recupero dei contenuti, validazione dell input, navigazione, dispatch View (statica o dinamica)
Service To Worker Strategia dispatcher nel controller Quando la logica di dispatching non è complessa (es: è statica) è possibile inserirla direttamente nel controller
Data Access Object Contesto I componenti di accesso ai dati variano a seconda della fonte dati (RDBMS, Flat File, ODBMS, ) Problema I componenti di accesso ai dati sono dipendenti dalla tecnologie delle sorgenti di dati: JDBC (per DB relazionali) EJB (per applicazioni Business 2 Businss) Web Services Quando la sorgente dei dati cambia tali componenti devono essere cambiati per gestire il nuovo tipo di sorgente Forze Tutti i casi in cui è necessario supportare Protected Variations rispetto alla sorgent dei dati Soluzione Usare un Data Access Object (DAO) per astrarre ed incapsulare la logica di accesso alla sorgente dei dati. Il DAO gestisce la connessione con la sorgente dei dati e ottiene e memorizza I dati
Data Access Object BusinessObject E un qualsiasi Client che richiede dati al DAO
Data Access Object
Data Access Object Strategia DAO Factory Quando la tecnologia usata per la persistenza non cambia è possibile usare un solo factory per tutti i DAO necessari alla applicazione
Data Access Object Strategia DAO Factory Quando la tecnologia usata per la persistenza cambiaè possibile usare il Pattern Abstract Factory (Gof)
Data Access Object Esempio (DAO Factory)
Data Access Object Esempio (DAO Abstract Factory)
Data Access Object Esempio (DAO Abstract Factory) public abstract class DAOFactory { public static final int CLOUDSCAPE = 1; public static final int ORACLE = 2; public static final int SYBASE = 3; // Un metodo per ogni DAO public abstract CustomerDAO getcustomerdao(); public abstract AccountDAO getaccountdao(); public abstract OrderDAO getorderdao();... public static DAOFactory getdaofactory(int whichfactory) { switch (whichfactory) { case CLOUDSCAPE: return new CloudscapeDAOFactory(); case ORACLE : return new OracleDAOFactory(); case SYBASE : return new SybaseDAOFactory(); default :
Data Access Object Esempio (DAO Abstract Factory) public class CloudscapeDAOFactory extends DAOFactory { public static final String DRIVER= "COM.cloudscape.core.RmiJdbcDriver"; public static final String DBURL jdbc:cloudscape:rmi://localhost:1099/j2eedb"; public static Connection createconnection() { // Qui ci va il codice di creazione della connection public CustomerDAO getcustomerdao() { return new CloudscapeCustomerDAO(); public AccountDAO getaccountdao() { return new CloudscapeAccountDAO(); public OrderDAO getorderdao() { return new CloudscapeOrderDAO();...
Data Access Object Esempio (DAO Abstract Factory) public interface CustomerDAO { public int insertcustomer(...); public boolean deletecustomer(...); public Customer findcustomer(...); public boolean updatecustomer(...); public RowSet selectcustomersrs(...); public Collection selectcustomersto(...);...
Data Access Object Esempio (DAO Abstract Factory) public class CloudscapeCustomerDAO implements CustomerDAO { public CloudscapeCustomerDAO() { // initialization public int insertcustomer(...) { // implementazione public boolean deletecustomer(...) { // implementazione public Customer findcustomer(...) { public Collection selectcustomersto(...) { // Implementazione: ritorna una Collection di DTO...
Data Access Object Esempio (DAO Abstract Factory) public class Customer implements java.io.serializable { int CustomerNumber; String name; String streetaddress; String city;... // metodi getter e setter......
Data Access Object Esempio (DAO Abstract Factory) // creo il DAO Factory DAOFactory cloudscapefactory = DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE); // Creo un DAO CustomerDAO custdao = cloudscapefactory.getcustomerdao(); // creo un nuovo customer int newcustno = custdao.insertcustomer(...); // cerco un customer. Mi viene restituito un DTO Customer cust = custdao.findcustomer(...); cust.setaddress(...); // modifico il DTO cust.setemail(...); // aggiorno le informazioni custdao.updatecustomer(cust); // cancello un customer... custdao.deletecustomer(...);
Business Delegate Contesto Un sistema prevede l invocazione di servizi I client devono gestire la complessità dell accesso ai servizi Problema Se i componenti dello strato di presentazione invocano direttamente i servizi di business distribuiti Forze I componenti dello strato di presentazione sono fragili rispetto ai cambiamenti dell implementazione dei servizi di business Potrebbe esserci un basso livello di performance per mancanza di caching I componenti dello strato di presentazione devono accedere a servizi di business Le API dei servizi di business potrebbero cambiare con l evoluzione dei requisiti E opportuno implementare dei meccanismi di caching per ridurre il traffico di rete tra i client ed i servizi di business
Business Delegate Soluzione Usare un Business Delegate per ridurre l accoppiamento tra strato di presentazione e i servizi di business. Il Business Delegate nasconde i dettagli di implementazione di lookup e accesso di servizi di business Il LookupService può essere parte del BusinessDelegate o un Componente separato (come propone il Pattern Service Locator)
Business Delegate
Service Locator Contesto Necessità di incapsulare il lookup di servizi di business Problema Delocalizzare il servizio Disaccoppiare il client dal problema di recuperare un riferimento del servizio
Service Locator Soluzione Si usi un Service Locator per nascondere la complessità del lookup di oggetti service Più client possono riusare il Service Locator per ridurre la complessità, avere un unico punto di controllo e migliorare le performance con meccanismi di caching
Service Locator